1 // Hxt - Copyright (C)
2 // 2016 - 2020 UCLouvain
3 //
4 // See the LICENSE.txt file for license information.
5 //
6 // Contributor(s):
7 //   Célestin Marot
8 
9 #include "hxt_edgeRemoval.h"
10 #include "hxt_tetFlag.h"
11 
12 
13 #define NV -128                // not a valid entry
14 #define HXT_EDGE_REMOVAL_MAX 7 // you cannot increase it above 7 ATM
15 
16 typedef struct { // bipyramidal cavity for the edge-removal
17     uint64_t neigh_up  [HXT_EDGE_REMOVAL_MAX];
18     uint64_t neigh_down[HXT_EDGE_REMOVAL_MAX];
19     uint16_t flag      [HXT_EDGE_REMOVAL_MAX];
20     uint32_t annulus   [HXT_EDGE_REMOVAL_MAX];
21     uint32_t v_up;
22     uint32_t v_down;
23     uint32_t num;
24 } HXTBipyramid;
25 
26 
27 /*
28 An oriented edge {up,down} is described by its 'in' and 'out' facets :
29 (hxt_tetFlag.h is of little help, because edge constraints are not oriented)
30 
31 
32        v_up
33        |\`-_
34        | \  `-_
35        |  \    `-_                in_facet
36        |   \      `-_              |
37        |    \   up   `-_          /
38        |     \  facet   `-_   <--'
39 our    |      \            `-_
40 edge   | out   \              `-_
41 -----> | facet  \v_out__________`>v_in
42        |        /               _-'
43        |       /             _-'
44        |      /  down     _-'
45        |     /  facet  _-'
46        |    /       _-'
47        |   /     _-'
48        |  /   _-'
49        | / _-'
50        |/-'
51       v_down
52 
53     _->
54    /
55    \    we scan tetrahedra in a counterclockwise order when viewed from up
56     `-__-'
57 
58 
59  We keep the numbering of facets and the orientation of tetrahedra as before so:
60 
61  mesh->tetrahedra.node[4*t + in_facet] = v_out
62  mesh->tetrahedra.node[4*t + out_facet] = v_in
63  mesh->tetrahedra.node[4*t + down_facet] = v_up
64  mesh->tetrahedra.node[4*t + up_facet] = v_down
65 
66 
67 There are 12 possible oriented edges (in_facet!=out_facet)
68 There are also 12 possibilities for a valid tetrahedra, each can be uniquely defined by an oriented edge...
69 
70 in_f=0 out_f=1 up_f=2 down_f=3    in_f=0 out_f=2 up_f=3 down_f=1     in_f=0 out_f=3 up_f=1 down_f=2
71       v_3                              v_1                              v_2
72        |\`-_                            |\`-_                            |\`-_
73        | \  `-_                         | \  `-_                         | \  `-_
74        |  \    `-_                      |  \    `-_                      |  \    `-_
75        |   \      `-_                   |   \      `-_                   |   \      `-_
76        |    \        `-_                |    \        `-_                |    \        `-_
77        |     \v_0_______`>v_1           |     \v_0_______`>v_2           |     \v_0_______`>v_3
78        |     /         _-'              |     /         _-'              |     /         _-'
79        |    /       _-'                 |    /       _-'                 |    /       _-'
80        |   /     _-'                    |   /     _-'                    |   /     _-'
81        |  /   _-'                       |  /   _-'                       |  /   _-'
82        | / _-'                          | / _-'                          | / _-'
83        |/-'                             |/-'                             |/-'
84       v_2                              v_3                              v_1
85 
86 
87 in_f=1 out_f=2 up_f=0 down_f=3    in_f=1 out_f=0 up_f=3 down_f=2     in_f=1 out_f=3 up_f=2 down_f=0
88       v_3                              v_2                              v_0
89        |\`-_                            |\`-_                            |\`-_
90        | \  `-_                         | \  `-_                         | \  `-_
91        |  \    `-_                      |  \    `-_                      |  \    `-_
92        |   \      `-_                   |   \      `-_                   |   \      `-_
93        |    \        `-_                |    \        `-_                |    \        `-_
94        |     \v_1_______`>v_2           |     \v_1_______`>v_0           |     \v_1_______`>v_3
95        |     /         _-'              |     /         _-'              |     /         _-'
96        |    /       _-'                 |    /       _-'                 |    /       _-'
97        |   /     _-'                    |   /     _-'                    |   /     _-'
98        |  /   _-'                       |  /   _-'                       |  /   _-'
99        | / _-'                          | / _-'                          | / _-'
100        |/-'                             |/-'                             |/-'
101       v_0                              v_3                              v_2
102 
103 
104 in_f=2 out_f=3 up_f=0 down_f=1    in_f=2 out_f=0 up_f=1 down_f=3     in_f=2 out_f=1 up_f=3 down_f=0
105       v_1                              v_3                              v_0
106        |\`-_                            |\`-_                            |\`-_
107        | \  `-_                         | \  `-_                         | \  `-_
108        |  \    `-_                      |  \    `-_                      |  \    `-_
109        |   \      `-_                   |   \      `-_                   |   \      `-_
110        |    \        `-_                |    \        `-_                |    \        `-_
111        |     \v_3_______`>v_2           |     \v_2_______`>v_0           |     \v_2_______`>v_1
112        |     /         _-'              |     /         _-'              |     /         _-'
113        |    /       _-'                 |    /       _-'                 |    /       _-'
114        |   /     _-'                    |   /     _-'                    |   /     _-'
115        |  /   _-'                       |  /   _-'                       |  /   _-'
116        | / _-'                          | / _-'                          | / _-'
117        |/-'                             |/-'                             |/-'
118       v_0                              v_1                              v_3
119 
120 
121 in_f=3 out_f=1 up_f=0 down_f=2    in_f=3 out_f=0 up_f=2 down_f=1     in_f=3 out_f=2 up_f=1 down_f=0
122       v_2                              v_1                              v_0
123        |\`-_                            |\`-_                            |\`-_
124        | \  `-_                         | \  `-_                         | \  `-_
125        |  \    `-_                      |  \    `-_                      |  \    `-_
126        |   \      `-_                   |   \      `-_                   |   \      `-_
127        |    \        `-_                |    \        `-_                |    \        `-_
128        |     \v_2_______`>v_1           |     \v_3_______`>v_0           |     \v_3_______`>v_2
129        |     /         _-'              |     /         _-'              |     /         _-'
130        |    /       _-'                 |    /       _-'                 |    /       _-'
131        |   /     _-'                    |   /     _-'                    |   /     _-'
132        |  /   _-'                       |  /   _-'                       |  /   _-'
133        | / _-'                          | / _-'                          | / _-'
134        |/-'                             |/-'                             |/-'
135       v_0                              v_2                              v_1
136 */
137 
138 static const int _UP_FACET[4][4] = {{NV, 2, 3, 1},
139                                     { 3,NV, 0, 2},
140                                     { 1, 3,NV, 0},
141                                     { 2, 0, 1,NV}};
142 
143 #define UP_FACET(in_facet, out_facet) _UP_FACET[in_facet][out_facet]
144 #define DOWN_FACET(in_facet, out_facet) _UP_FACET[out_facet][in_facet]
145 
146 #define UP_VERTEX(in_facet, out_facet) DOWN_FACET(in_facet, out_facet)
147 #define DOWN_VERTEX(in_facet, out_facet) UP_FACET(in_facet, out_facet)
148 #define IN_VERTEX(in_facet, out_facet) (out_facet)
149 #define OUT_VERTEX(in_facet, out_facet) (in_facet)
150 
151 /* that's everything we need to handle edges !
152 
153  NOW, we need patterns of triangulation around edges to make swaps
154  */
155 
156 typedef struct {
157   const unsigned char (*triangles)[3];      /* triangles array                                     */
158   const uint64_t *triangle_in_triangul;     /* in which triangulation is the triangles (bit array) */
159   const unsigned char (*triangulations)[5]; /* triangulation array                                 */
160   const signed char (*triangul_neigh)[20];  /* array to find adjacencies back                      */
161   /* further explanation because triangul_neigh is weird :
162    * if the number n is positive:
163    *   - the neighbor is a new tet. (the face is not a boundary face of the cavity)
164    *   - the index of the neighbor in the triangulation is n/4
165    *   - the index of the edge in the neighbor triangle is n%4
166    *   (- we could have use n/3 and n%3 but %4 is faster)
167    *
168    * if the number n is negative
169    *   - the neighbor is a old tet. a tet outside the boundary of the cavity
170    *   - the index of the neighbor-number in the list of neighbor is directly -n-1
171    *
172    */
173 
174   const unsigned num_triangles;             /* number of different triangles                       */
175   const unsigned num_triangulations ;       /* number of different triangulations                  */
176   // const int num_triangles_per_triangulation; /* simply the number of nodes +2...              */
177 } SwapPattern ;
178 
179 
180 static const unsigned char triangles3[][3] = { {0,1,2} };
181 static const uint64_t triangle_in_triangul3[] = { 1};
182 static const unsigned char triangulations3[][5] = {{0}};
183 static const signed char triangul_neigh3[][20] = {
184   {-2,-3,-1,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV}
185 };
186 
187 
188 static const unsigned char triangles4[][3] = {
189   {0,1,2}, {2,3,0}, {1,2,3}, {3,0,1}
190 };
191 static const uint64_t triangle_in_triangul4[] = { 1, 1, 2, 2};
192 static const unsigned char triangulations4[][5] = {
193   {0,1}, {2,3}
194 };
195 static const signed char triangul_neigh4[][20] = {
196   {-2,5,-1,NV,-4,1,-3,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV},
197   {-3,5,-2,NV,-1,1,-4,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV,NV}
198 };
199 
200 
201 
202 static const unsigned char triangles5[][3] = {
203   {0,1,2}, {0,2,3}, {0,3,4}, {0,1,4}, {1,3,4},
204   {1,2,3}, {2,3,4}, {0,2,4}, {0,1,3}, {1,2,4}
205 };
206 static const uint64_t triangle_in_triangul5[] = {5, 1, 9, 18, 2, 10, 20, 4, 8, 16};
207 static const unsigned char triangulations5[][5] = { {0,1,2}, {3,4,5}, {0,6,7}, {2,5,8}, {3,6,9} };
208 static const signed char triangul_neigh5[][20] = {
209   {-2,6,-1,NV,-3,10,1,NV,-4,-5,5,NV,NV,NV,NV,NV,NV,NV,NV,NV},
210   {5,-5,-1,NV,-4,0,9,NV,-3,6,-2,NV,NV,NV,NV,NV,NV,NV,NV,NV},
211   {-2,10,-1,NV,-4,8,-3,NV,5,-5,1,NV,NV,NV,NV,NV,NV,NV,NV,NV},
212   {-4,-5,9,NV,-3,8,-2,NV,5,2,-1,NV,NV,NV,NV,NV,NV,NV,NV,NV},
213   {9,-5,-1,NV,-4,8,-3,NV,5,0,-2,NV,NV,NV,NV,NV,NV,NV,NV,NV}
214 };
215 
216 
217 static const unsigned char triangles6[][3] = {
218   {0,1,2}, {0,2,3}, {0,3,4}, {0,4,5}, {0,2,5}, {2,4,5}, {2,3,4}, {0,3,5},
219   {3,4,5}, {0,2,4}, {2,3,5}, {1,2,3}, {0,1,3}, {0,1,5}, {1,4,5}, {1,3,4},
220   {0,1,4}, {1,3,5}, {1,2,4}, {1,2,5}
221 };
222 static const uint64_t triangle_in_triangul6[] = {
223   31, 5, 33, 2345, 18, 4098, 7178, 132, 8852, 8, 8208,
224   992, 160, 13888, 1088, 320, 2304, 512, 3072, 12288};
225 static const unsigned char triangulations6[][5] = {
226   {0,1,2,3}, {0,4,5,6}, {0,1,7,8}, {0,3,6,9}, {0,4,8,10},
227   {2,3,11,12}, {11,13,14,15}, {7,8,11,12}, {3,11,15,16},
228   {8,11,13,17}, {6,13,14,18}, {3,6,16,18}, {5,6,13,19},
229   {8,10,13,19}
230 };
231 static const signed char triangul_neigh6[][20] = {
232   {-2,6,-1,NV,-3,10,1,NV,-4,14,5,NV,-5,-6,9,NV,NV,NV,NV,NV},
233   {-2,6,-1,NV,9,-6,1,NV,-5,4,13,NV,-4,10,-3,NV,NV,NV,NV,NV},
234   {-2,6,-1,NV,-3,10,1,NV,13,-6,5,NV,-5,8,-4,NV,NV,NV,NV,NV},
235   {-2,14,-1,NV,-5,-6,13,NV,-4,12,-3,NV,9,6,1,NV,NV,NV,NV,NV},
236   {-2,6,-1,NV,13,-6,1,NV,-5,12,-4,NV,9,4,-3,NV,NV,NV,NV,NV},
237   {-4,6,13,NV,-5,-6,1,NV,-3,12,-2,NV,9,2,-1,NV,NV,NV,NV,NV},
238   {-3,14,-2,NV,9,-6,-1,NV,-5,4,13,NV,-4,10,1,NV,NV,NV,NV,NV},
239   {5,-6,13,NV,-5,0,-4,NV,-3,12,-2,NV,9,2,-1,NV,NV,NV,NV,NV},
240   {-5,-6,13,NV,-3,10,-2,NV,-4,12,5,NV,9,2,-1,NV,NV,NV,NV,NV},
241   {-5,12,-4,NV,-3,14,-2,NV,13,-6,-1,NV,1,8,5,NV,NV,NV,NV,NV},
242   {-4,12,-3,NV,9,-6,-1,NV,-5,4,13,NV,1,10,-2,NV,NV,NV,NV,NV},
243   {-5,-6,9,NV,-4,12,-3,NV,13,2,-1,NV,5,8,-2,NV,NV,NV,NV,NV},
244   {-5,12,5,NV,-4,2,-3,NV,13,-6,-1,NV,1,8,-2,NV,NV,NV,NV,NV},
245   {-5,4,-4,NV,1,12,-3,NV,13,-6,-1,NV,5,8,-2,NV,NV,NV,NV,NV}
246 };
247 
248 
249 static const unsigned char triangles7[][3] = {
250   {0,1,2}, {0,2,3}, {0,3,4}, {0,4,5}, {0,5,6}, {0,3,6}, {3,5,6}, {3,4,5}, {0,4,6},
251   {4,5,6}, {0,3,5}, {3,4,6}, {0,2,4}, {2,3,4}, {0,2,6}, {2,5,6}, {2,4,5}, {0,2,5},
252   {2,4,6}, {2,3,5}, {2,3,6}, {0,1,3}, {1,2,3}, {0,1,4}, {1,3,4}, {0,1,6}, {1,5,6},
253   {1,4,5}, {0,1,5}, {1,4,6}, {1,3,5}, {1,3,6}, {1,2,4}, {1,2,5}, {1,2,6}
254 };
255 static const uint64_t triangle_in_triangul7[] = {
256   16383, 31, 81925, 268976161, 294512118057, 294930, 1099578773506, 2061701913610,
257   1075904644, 2273256481428, 131080, 2199157743632, 160, 137170519008, 13888, 584115553344,
258   60129542464, 2304, 68719477248, 962072677376, 3298534895616, 507904, 268419072, 1344798720,
259   16252928, 4102458179584, 146583584768, 2689597440, 294243008512, 4303355904, 50331648, 201326592,
260   8321499136, 438086664192, 3951369912320
261  };
262 static const unsigned char triangulations7[][5] = {
263   {0,1,2,3,4}, {0,1,5,6,7}, {0,1,2,8,9}, {0,1,4,7,10}, {0,1,5,9,11}, {0,3,4,12,13},
264   {0,13,14,15,16}, {0,8,9,12,13}, {0,4,13,16,17}, {0,9,13,14,18}, {0,7,14,15,19},
265   {0,4,7,17,19}, {0,6,7,14,20}, {0,9,11,14,20}, {2,3,4,21,22}, {5,6,7,21,22},
266   {2,8,9,21,22}, {4,7,10,21,22}, {5,9,11,21,22}, {3,4,22,23,24}, {22,24,25,26,27},
267   {8,9,22,23,24}, {4,22,24,27,28}, {9,22,24,25,29}, {7,22,25,26,30}, {4,7,22,28,30},
268   {6,7,22,25,31}, {9,11,22,25,31}, {3,4,13,23,32}, {13,25,26,27,32}, {8,9,13,23,32},
269   {4,13,27,28,32}, {9,13,25,29,32}, {13,16,25,26,33}, {4,13,16,28,33},
270   {13,15,16,25,34}, {9,13,18,25,34}, {7,19,25,26,33}, {4,7,19,28,33},
271   {7,15,19,25,34}, {6,7,20,25,34}, {9,11,20,25,34}
272 };
273 static const signed char triangul_neigh7[][20] = {
274   {-2,6,-1,NV,-3,10,1,NV,-4,14,5,NV,-5,18,9,NV,-6,-7,13,NV},
275   {-2,6,-1,NV,-3,10,1,NV,13,-7,5,NV,-6,8,17,NV,-5,14,-4,NV},
276   {-2,6,-1,NV,-3,10,1,NV,-4,14,5,NV,17,-7,9,NV,-6,12,-5,NV},
277   {-2,6,-1,NV,-3,18,1,NV,-6,-7,17,NV,-5,16,-4,NV,13,10,5,NV},
278   {-2,6,-1,NV,-3,10,1,NV,17,-7,5,NV,-6,16,-5,NV,13,8,-4,NV},
279   {-2,14,-1,NV,-5,10,13,NV,-6,-7,5,NV,17,6,1,NV,-4,12,-3,NV},
280   {-2,10,-1,NV,-4,18,-3,NV,13,-7,1,NV,-6,8,17,NV,-5,14,5,NV},
281   {-2,14,-1,NV,9,-7,13,NV,-6,4,-5,NV,17,6,1,NV,-4,12,-3,NV},
282   {-2,18,-1,NV,-6,-7,17,NV,-4,14,-3,NV,-5,16,9,NV,13,6,1,NV},
283   {-2,14,-1,NV,-6,16,-5,NV,-4,18,-3,NV,17,-7,1,NV,5,12,9,NV},
284   {-2,10,-1,NV,-5,16,-4,NV,13,-7,1,NV,-6,8,17,NV,5,14,-3,NV},
285   {-2,14,-1,NV,-6,-7,13,NV,-5,16,-4,NV,17,6,1,NV,9,12,-3,NV},
286   {-2,14,-1,NV,-6,16,9,NV,-5,6,-4,NV,17,-7,1,NV,5,12,-3,NV},
287   {-2,14,-1,NV,-6,8,-5,NV,5,16,-4,NV,17,-7,1,NV,9,12,-3,NV},
288   {-4,6,13,NV,-5,10,1,NV,-6,-7,5,NV,17,2,-1,NV,-3,12,-2,NV},
289   {5,-7,13,NV,-6,0,9,NV,-5,6,-4,NV,17,2,-1,NV,-3,12,-2,NV},
290   {-4,6,13,NV,9,-7,1,NV,-6,4,-5,NV,17,2,-1,NV,-3,12,-2,NV},
291   {-6,-7,9,NV,-5,8,-4,NV,5,2,13,NV,17,10,-1,NV,-3,12,-2,NV},
292   {9,-7,13,NV,-6,8,-5,NV,5,0,-4,NV,17,2,-1,NV,-3,12,-2,NV},
293   {-5,6,13,NV,-6,-7,1,NV,-3,18,-2,NV,17,2,-1,NV,-4,12,9,NV},
294   {-3,6,-2,NV,-4,18,1,NV,13,-7,-1,NV,-6,8,17,NV,-5,14,5,NV},
295   {5,-7,13,NV,-6,0,-5,NV,-3,18,-2,NV,17,2,-1,NV,-4,12,9,NV},
296   {-6,-7,17,NV,-3,10,-2,NV,-4,14,5,NV,-5,16,9,NV,13,2,-1,NV},
297   {-6,16,-5,NV,-3,10,-2,NV,-4,18,5,NV,17,-7,-1,NV,1,12,9,NV},
298   {-5,16,-4,NV,-3,18,-2,NV,13,-7,-1,NV,-6,8,17,NV,1,14,5,NV},
299   {-6,-7,13,NV,-5,16,-4,NV,-3,18,-2,NV,17,2,-1,NV,5,12,9,NV},
300   {-6,16,5,NV,-5,2,-4,NV,-3,18,-2,NV,17,-7,-1,NV,1,12,9,NV},
301   {-6,4,-5,NV,1,16,-4,NV,-3,18,-2,NV,17,-7,-1,NV,5,12,9,NV},
302   {-5,6,13,NV,-6,-7,1,NV,-4,16,-3,NV,17,2,-1,NV,9,12,-2,NV},
303   {-4,16,-3,NV,9,-7,-1,NV,-6,4,13,NV,-5,10,17,NV,1,14,-2,NV},
304   {5,-7,13,NV,-6,0,-5,NV,-4,16,-3,NV,17,2,-1,NV,9,12,-2,NV},
305   {-6,-7,13,NV,-4,16,-3,NV,-5,12,17,NV,9,2,-1,NV,5,10,-2,NV},
306   {-6,12,-5,NV,-4,16,-3,NV,13,-7,-1,NV,1,8,17,NV,5,14,-2,NV},
307   {-4,6,-3,NV,-5,16,1,NV,13,-7,-1,NV,-6,8,17,NV,5,14,-2,NV},
308   {-6,-7,13,NV,-4,10,-3,NV,-5,16,5,NV,17,2,-1,NV,9,12,-2,NV},
309   {-4,10,-3,NV,-6,16,9,NV,-5,6,1,NV,17,-7,-1,NV,5,12,-2,NV},
310   {-6,8,-5,NV,-4,10,-3,NV,1,16,5,NV,17,-7,-1,NV,9,12,-2,NV},
311   {-5,4,-4,NV,1,16,-3,NV,13,-7,-1,NV,-6,8,17,NV,5,14,-2,NV},
312   {-6,-7,13,NV,-5,8,-4,NV,5,16,-3,NV,17,2,-1,NV,9,12,-2,NV},
313   {-5,8,-4,NV,-6,16,9,NV,1,6,-3,NV,17,-7,-1,NV,5,12,-2,NV},
314   {-6,8,5,NV,-5,2,-4,NV,1,16,-3,NV,17,-7,-1,NV,9,12,-2,NV},
315   {-6,4,-5,NV,1,8,-4,NV,5,16,-3,NV,17,-7,-1,NV,9,12,-2,NV}
316 };
317 
318 
319 static const SwapPattern patterns[8] = {
320   {0},{0},{0},
321   {
322     // pattern with 3 points around edge  | 3 tetra in, 2 tetra out
323     .triangles = triangles3,
324     .num_triangles = 1,
325     .triangulations = triangulations3,
326     .num_triangulations = 1,
327     .triangul_neigh = triangul_neigh3,
328     .triangle_in_triangul = triangle_in_triangul3
329   },
330 
331   {
332     // pattern with 4 points around edge  | 4 tetra in, 4 tetra out
333     .triangles = triangles4,
334     .num_triangles = 4,
335     .triangulations = triangulations4,
336     .num_triangulations = 2,
337     .triangul_neigh = triangul_neigh4,
338     .triangle_in_triangul = triangle_in_triangul4
339   },
340 
341   {
342     // pattern with 5 points around edge  | 5 tetra in, 6 tetra out
343     .triangles = triangles5,
344     .num_triangles = 10,
345     .triangulations = triangulations5,
346     .num_triangulations = 5,
347     .triangul_neigh = triangul_neigh5,
348     .triangle_in_triangul = triangle_in_triangul5
349   },
350 
351   {
352     // pattern with 6 points around edge
353     .triangles = triangles6,
354     .num_triangles = 20,
355     .triangulations = triangulations6,
356     .num_triangulations = 14,
357     .triangul_neigh = triangul_neigh6,
358     .triangle_in_triangul = triangle_in_triangul6
359   },
360 
361   {
362     // pattern with 7 points around edge
363     .triangles = triangles7,
364     .num_triangles = 35,
365     .triangulations = triangulations7,
366     .num_triangulations = 42, // see Catalan numbers ;)
367     .triangul_neigh = triangul_neigh7,
368     .triangle_in_triangul = triangle_in_triangul7
369   }
370 };
371 
372 
373 /**************** that's it for the DATAs ****************/
374 
375 
376 /**************************************************************************
377                     edge-removal related functions
378  **************************************************************************/
379 
380 /* create a cavity containing all tetrahedra around an edge, by turning around it */
buildERCavity(ThreadLocal * local,HXTBipyramid * cavity,const uint64_t badTet,unsigned in_facet,unsigned out_facet)381 static inline HXTStatus buildERCavity(ThreadLocal* local,
382                                       HXTBipyramid* cavity,
383                                       const uint64_t badTet,
384                                       unsigned in_facet, unsigned out_facet)
385 {
386   const uint64_t startDist = local->partition.startDist;
387   const uint64_t rel = local->partition.lengthDist;
388   int edgeOut = 0;
389   HXTMesh* mesh = local->toSync->mesh;
390   HXTDeleted* deleted = &local->deleted;
391   HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord;
392 
393   uint64_t curTet = badTet;
394   cavity->num = 0;
395 
396   if(getEdgeConstraint(mesh, badTet, getEdgeFromFacets(in_facet, out_facet)))
397     return HXT_STATUS_CONSTRAINT;
398 
399   cavity->v_up = mesh->tetrahedra.node[4*badTet + UP_VERTEX(in_facet, out_facet)];
400   edgeOut += vertexOutOfPartition(vertices, cavity->v_up, rel, startDist);
401   cavity->v_down = mesh->tetrahedra.node[4*badTet + DOWN_VERTEX(in_facet, out_facet)];
402   edgeOut += vertexOutOfPartition(vertices, cavity->v_down, rel, startDist);
403 
404   HXT_CHECK( askForDeleted(deleted, 7) );
405 
406   do{
407     // first, verify that the tetrahedra is not in the buffer zone between partitions
408     uint32_t oldV = mesh->tetrahedra.node[4*curTet + out_facet];
409     uint32_t newV = mesh->tetrahedra.node[4*curTet + in_facet];
410 
411     if(vertexOutOfPartition(vertices, oldV, rel, startDist) +
412        vertexOutOfPartition(vertices, newV, rel, startDist) + edgeOut > 1) {
413       return HXT_STATUS_CONFLICT;
414     }
415 
416     // add the current tetrahedra
417     deleted->array[deleted->num + cavity->num] = curTet;
418 
419     {
420       unsigned up_facet = UP_FACET(in_facet, out_facet);
421       unsigned down_facet = DOWN_FACET(in_facet, out_facet);
422 
423       // add the neighbor up and down
424       cavity->neigh_up[cavity->num] = mesh->tetrahedra.neigh[4*curTet + up_facet];
425       cavity->neigh_down[cavity->num] = mesh->tetrahedra.neigh[4*curTet + down_facet];
426 
427       int upDownEdge = getEdgeFromFacets(up_facet, down_facet);
428       int upOutEdge = getEdgeFromFacets(up_facet, out_facet);
429       int upInEdge = getEdgeFromFacets(up_facet, in_facet);
430       int downOutEdge = getEdgeFromFacets(down_facet, out_facet);
431       int downInEdge = getEdgeFromFacets(down_facet, in_facet);
432 
433 
434       // TODO: just store one flag for up and down. the one of the default tetrahedron
435       cavity->flag[cavity->num] = (getFacetConstraint(mesh, curTet, up_facet)!=0) +
436                                             ((getEdgeConstraint(mesh, curTet, upOutEdge)!=0)<<1) +
437                                             ((getEdgeConstraint(mesh, curTet, upDownEdge)!=0)<<2) +
438                                             ((getEdgeConstraint(mesh, curTet, upInEdge)!=0)<<3) +
439                                             ((getFacetConstraint(mesh, curTet, down_facet)!=0)<<4) +
440                                             ((getEdgeConstraint(mesh, curTet, downOutEdge)!=0)<<5) +
441                                             ((getEdgeConstraint(mesh, curTet, downInEdge)!=0)<<6) +
442                                             ((getEdgeConstraint(mesh, curTet, upDownEdge)!=0)<<7);
443     }
444     // add the annulus vertex
445     cavity->annulus[cavity->num] = oldV;
446     cavity->num++;
447 
448     // go into the neighbor through out_facet
449     uint64_t neigh = mesh->tetrahedra.neigh[4*curTet + out_facet];
450     if(neigh == HXT_NO_ADJACENT
451       || (getFacetConstraint(mesh, curTet, out_facet)!=0)) {
452       return HXT_STATUS_CONSTRAINT;
453     }
454 
455     if(cavity->num>=HXT_EDGE_REMOVAL_MAX)
456       return HXT_STATUS_INTERNAL;
457 
458     curTet = neigh/4;
459     in_facet = neigh%4;
460 
461     uint32_t* nodes = mesh->tetrahedra.node + 4*curTet;
462 
463     for (out_facet=0; out_facet<3; out_facet++)
464       if(nodes[out_facet]==newV)
465         break;
466 
467   }while(curTet!=badTet);
468 
469   return HXT_STATUS_OK;
470 }
471 
472 
473 
474 
475 /* perform the edge removal, also called edge swap */
hxtEdgeRemoval_opti(ThreadLocal * local,uint64_t badTet,unsigned edgeID)476 HXTStatus hxtEdgeRemoval_opti(ThreadLocal* local,
477                               uint64_t badTet,
478                               unsigned edgeID)
479 {
480   unsigned in_facet, out_facet;
481   getFacetsFromEdge(edgeID, &in_facet, &out_facet);
482   HXTMesh* mesh = local->toSync->mesh;
483   HXTDeleted* deleted = &local->deleted;
484   double* qualityArray = local->quality->values;
485 
486   HXTBipyramid cavity;
487   HXT_CHECK( buildERCavity(local, &cavity, badTet, in_facet, out_facet) );
488 
489   // find worst quality tet of the cavity
490   double worst = DBL_MAX;
491   for (uint32_t i=0; i<cavity.num; i++) {
492     uint64_t tet = deleted->array[deleted->num+i];
493     double qual = qualityArray[tet];
494     if(qual<worst)
495       worst = qual;
496   }
497 
498   const SwapPattern* patt = &patterns[cavity.num];
499   const unsigned num_triangle_per_triangul = cavity.num-2;
500   uint32_t* annulus = cavity.annulus;
501 
502   // calculate qualities of all possible tetrahedra
503   double hxtDeclareAligned qual_up[35];
504   double hxtDeclareAligned qual_down[35];
505   uint64_t mask = 0;
506   for (unsigned i=0; i<patt->num_triangles; i++) {
507     uint32_t p0 = annulus[patt->triangles[i][0]];
508     uint32_t p1 = annulus[patt->triangles[i][1]];
509     uint32_t p2 = annulus[patt->triangles[i][2]];
510 
511     // printf("%u %u %u\n", p0, p1, p2);
512 
513     qual_up[i] = tetQuality(mesh, local->quality, p0, p1, cavity.v_up, p2);
514     qual_down[i] = tetQuality(mesh, local->quality, p0, p1, p2, cavity.v_down);
515 
516     if(qual_up[i]<=worst || qual_down[i]<=worst)
517       mask |= patt->triangle_in_triangul[i];
518   }
519 
520   // find the best triangulation
521   int best_triangulation = -1;
522   double best_worst = 0;
523   for (unsigned i=0; i<patt->num_triangulations; i++) {
524     if((mask & (UINT64_C(1)<<i))==0) {
525       double cur_worst = DBL_MAX;
526       // this mean that no triangle in the triangulation
527       //   is worst than the current worst tetrahedron
528       for (unsigned j=0; j<num_triangle_per_triangul; j++) {
529         double q_u = qual_up[patt->triangulations[i][j]];
530         double q_d = qual_down[patt->triangulations[i][j]];
531         if(q_u<best_worst || q_d<best_worst){
532           cur_worst = 0;
533           break;
534         }
535         if(q_u<cur_worst)
536           cur_worst = q_u;
537         if(q_d<cur_worst)
538           cur_worst = q_d;
539       }
540 
541       if(cur_worst > best_worst){
542         best_worst = cur_worst;
543         best_triangulation = i;
544       }
545     }
546   }
547 
548   // if no triangulation are better, return
549   if(best_triangulation==-1) {
550     return HXT_STATUS_NOTBETTER;
551   }
552 
553   // mark new deleted tet as deleted
554   for (uint32_t i=0; i<cavity.num; i++) {
555     setDeletedFlag(mesh, deleted->array[deleted->num+i]);
556   }
557   deleted->num += cavity.num;
558 
559   // reserve enough tetrahedra
560   if(2*num_triangle_per_triangul > deleted->num){ // tetrahedra are created...
561     HXT_CHECK(createNewDeleted(local->toSync, deleted, 2*num_triangle_per_triangul) );
562   }
563 
564   uint64_t start = deleted->num - 2*num_triangle_per_triangul;
565   double color = mesh->tetrahedra.color[badTet];
566 
567   // make the swap
568   for (unsigned i=0; i<num_triangle_per_triangul; i++) {
569     uint32_t tri = patt->triangulations[best_triangulation][i];
570     uint32_t p0 = annulus[patt->triangles[tri][0]];
571     uint32_t p1 = annulus[patt->triangles[tri][1]];
572     uint32_t p2 = annulus[patt->triangles[tri][2]];
573 
574     // neighbor information. if positive, the neighbor is a new tetrahedra
575     int n0 = patt->triangul_neigh[best_triangulation][4*i];
576     int n1 = patt->triangul_neigh[best_triangulation][4*i+1];
577     int n2 = patt->triangul_neigh[best_triangulation][4*i+2];
578 
579     const uint64_t newTet_up = deleted->array[start + i*2];
580     const uint64_t newTet_down = deleted->array[start + i*2 + 1];
581 
582     // create the upper tet.
583     {
584       uint32_t* nodes = mesh->tetrahedra.node + 4*newTet_up;
585       uint64_t* neigh = mesh->tetrahedra.neigh + 4*newTet_up;
586 
587       mesh->tetrahedra.color[newTet_up] = color;
588       mesh->tetrahedra.flag[newTet_up] = 0;
589       qualityArray[newTet_up] = qual_up[tri];
590       local->date->values[newTet_up].creation = local->date->current;
591 
592       nodes[0] = p0;
593       nodes[1] = p1;
594       nodes[2] = cavity.v_up;
595       nodes[3] = p2;
596 
597       if(n0>=0){                                                     //  v   we add this because if n0%4==2 then it should be 3
598         neigh[0] = 4*deleted->array[start + (n0/4)*2] + (n0%4) + (n0%4)/2;
599       }
600       else {
601         neigh[0] = cavity.neigh_up[-n0-1];
602 
603         //  (down=2, in=3, out=1, up=0)
604         mesh->tetrahedra.flag[newTet_up] |= (cavity.flag[-n0-1]&UINT16_C(1))<<8 |// face (bit 0) is the up_facet => 0  (bit 8)
605                                             (cavity.flag[-n0-1]&UINT16_C(2))>>1 |// first edge (bit 1) was between up_facet and out_facet => 0-1  (bit 0)
606                                             (cavity.flag[-n0-1]&UINT16_C(4))>>1 |// second edge (bit 2) was between up_facet and down_facet => 0-2 (bit 1)
607                                             (cavity.flag[-n0-1]&UINT16_C(8))>>1; // third edge (bit 3) was between up_facet and in_facet => 0-3    (bit 2)
608 
609         if(neigh[0]!=HXT_NO_ADJACENT)
610           mesh->tetrahedra.neigh[neigh[0]] = 4*newTet_up + 0;
611       }
612       if(n1>=0){
613         neigh[1] = 4*deleted->array[start + (n1/4)*2] + (n1%4) + (n1%4)/2;
614       }
615       else {
616         neigh[1] = cavity.neigh_up[-n1-1];
617 
618         //  (down=2, in=0, out=3, up=1)
619         mesh->tetrahedra.flag[newTet_up] |= (cavity.flag[-n1-1]&UINT16_C(1))<<9 |// face (bit 0) is the up_facet => 1  (bit 9)
620                                             (cavity.flag[-n1-1]&UINT16_C(2))<<3 |// first edge (bit 1) was between up_facet and out_facet => 1-3   (bit 4)
621                                             (cavity.flag[-n1-1]&UINT16_C(4))<<1 |// second edge (bit 2) was between up_facet and down_facet => 1-2 (bit 3)
622                                             (cavity.flag[-n1-1]&UINT16_C(8))>>3; // third edge (bit 3) was between up_facet and in_facet => 0-1    (bit 0)
623 
624         if(neigh[1]!=HXT_NO_ADJACENT)
625           mesh->tetrahedra.neigh[neigh[1]] = 4*newTet_up + 1;
626       }
627       neigh[2] = newTet_down*4 + 3;
628       if(n2>=0){
629         neigh[3] = 4*deleted->array[start + (n2/4)*2] + (n2%4) + (n2%4)/2;
630       }
631       else {
632         neigh[3] = cavity.neigh_up[-n2-1];
633 
634         //  (down=2, in=1, out=0, up=3)
635         mesh->tetrahedra.flag[newTet_up] |= (cavity.flag[-n2-1]&UINT16_C(1))<<11 |// face (bit 0) is the up_facet => 3  (bit 11)
636                                             (cavity.flag[-n2-1]&UINT16_C(2))<<1  |// first edge (bit 1) was between up_facet and out_facet => 0-3   (bit 2)
637                                             (cavity.flag[-n2-1]&UINT16_C(4))<<3  |// second edge (bit 2) was between up_facet and down_facet => 2-3 (bit 5)
638                                             (cavity.flag[-n2-1]&UINT16_C(8))<<1;  // third edge (bit 3) was between up_facet and in_facet => 1-3    (bit 4)
639 
640         if(neigh[3]!=HXT_NO_ADJACENT)
641           mesh->tetrahedra.neigh[neigh[3]] = 4*newTet_up + 3;
642       }
643     }
644 
645     // create the down tet.
646     {
647       uint32_t* nodes = mesh->tetrahedra.node + 4*newTet_down;
648       uint64_t* neigh = mesh->tetrahedra.neigh + 4*newTet_down;
649 
650       mesh->tetrahedra.color[newTet_down] = color;
651       mesh->tetrahedra.flag[newTet_down] = 0;
652       qualityArray[newTet_down] = qual_down[tri];
653       local->date->values[newTet_down].creation = local->date->current;
654 
655       nodes[0] = p0;
656       nodes[1] = p1;
657       nodes[2] = p2;
658       nodes[3] = cavity.v_down;
659 
660       if(n0>=0){
661         neigh[0] = 4*deleted->array[start + (n0/4)*2 +1] + (n0%4);
662       }
663       else {
664         neigh[0] = cavity.neigh_down[-n0-1];
665 
666         //  (down=0, in=2, out=1, up=3)
667         mesh->tetrahedra.flag[newTet_down] |= (cavity.flag[-n0-1]&UINT16_C(16))<<4 |// face (bit 4) is the down_facet => 0  (bit 8)
668                                               (cavity.flag[-n0-1]&UINT16_C(32))>>5 |// first edge (bit 5) was between down_facet and out_facet => 0-1   (bit 0)
669                                               (cavity.flag[-n0-1]&UINT16_C(64))>>5 |// second edge (bit 6) was between down_facet and in_facet => 0-2   (bit 1)
670                                               (cavity.flag[-n0-1]&UINT16_C(128))>>5;// third edge (bit 7) was between down_facet and up_facet => 0-3    (bit 2)
671 
672         if(neigh[0]!=HXT_NO_ADJACENT)
673           mesh->tetrahedra.neigh[neigh[0]] = 4*newTet_down + 0;
674       }
675       if(n1>=0){
676         neigh[1] = 4*deleted->array[start + (n1/4)*2 +1] + (n1%4);
677       }
678       else {
679         neigh[1] = cavity.neigh_down[-n1-1];
680 
681         //  (down=1, in=0, out=2, up=3)
682         mesh->tetrahedra.flag[newTet_down] |= (cavity.flag[-n1-1]&UINT16_C(16))<<5 |// face (bit 4) is the down_facet => 1  (bit 9)
683                                               (cavity.flag[-n1-1]&UINT16_C(32))>>2 |// first edge (bit 5) was between down_facet and out_facet => 1-2   (bit 3)
684                                               (cavity.flag[-n1-1]&UINT16_C(64))>>6 |// second edge (bit 6) was between down_facet and in_facet => 0-1   (bit 0)
685                                               (cavity.flag[-n1-1]&UINT16_C(128))>>3;// third edge (bit 7) was between down_facet and up_facet => 1-3    (bit 4)
686 
687         if(neigh[1]!=HXT_NO_ADJACENT)
688           mesh->tetrahedra.neigh[neigh[1]] = 4*newTet_down + 1;
689       }
690       if(n2>=0){
691         neigh[2] = 4*deleted->array[start + (n2/4)*2 +1] + (n2%4);
692       }
693       else {
694         neigh[2] = cavity.neigh_down[-n2-1];
695 
696         //  (down=2, in=1, out=0, up=3)
697         mesh->tetrahedra.flag[newTet_down] |= (cavity.flag[-n2-1]&UINT16_C(16))<<6 |// face (bit 4) is the down_facet => 2*4  (bit 10)
698                                               (cavity.flag[-n2-1]&UINT16_C(32))>>4 |// first edge (bit 5) was between down_facet and out_facet => 0-2   (bit 1)
699                                               (cavity.flag[-n2-1]&UINT16_C(64))>>3 |// second edge (bit 6) was between down_facet and in_facet => 1-2   (bit 3)
700                                               (cavity.flag[-n2-1]&UINT16_C(128))>>2;// third edge (bit 7) was between down_facet and up_facet => 2-3    (bit 5)
701 
702         if(neigh[2]!=HXT_NO_ADJACENT)
703           mesh->tetrahedra.neigh[neigh[2]] = 4*newTet_down + 2;
704       }
705       neigh[3] = newTet_up*4 + 2;
706     }
707   }
708 
709   deleted->num = start;
710 
711   return HXT_STATUS_OK;
712 }