Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
swapgen_3d.c
Go to the documentation of this file.
1/* =============================================================================
2** This file is part of the mmg software package for the tetrahedral
3** mesh modification.
4** Copyright (c) Bx INP/CNRS/Inria/UBordeaux/UPMC, 2004-
5**
6** mmg is free software: you can redistribute it and/or modify it
7** under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation, either version 3 of the License, or
9** (at your option) any later version.
10**
11** mmg is distributed in the hope that it will be useful, but WITHOUT
12** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13** FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14** License for more details.
15**
16** You should have received a copy of the GNU Lesser General Public
17** License and of the GNU General Public License along with mmg (in
18** files COPYING.LESSER and COPYING). If not, see
19** <http://www.gnu.org/licenses/>. Please read their terms carefully and
20** use this copy of the mmg distribution only if you accept them.
21** =============================================================================
22*/
23
35#include "libmmg3d.h"
38
57MMG5_int MMG5_chkswpgen(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int start,int ia,
58 int *ilist,int64_t *list,double crit,int8_t typchk) {
59 MMG5_pTetra pt,pt0;
60 MMG5_pPoint p0;
61 double calold,calnew,caltmp;
62 int npol,k,l;
63 MMG5_int np,na,nb,piv,*adja,adj,pol[MMG3D_LMAX+2],iel,refdom;
64 int8_t i,ip,ier,ifac;
65
66 pt = &mesh->tetra[start];
67 refdom = pt->ref;
68
69 pt0 = &mesh->tetra[0];
70 na = pt->v[MMG5_iare[ia][0]];
71 nb = pt->v[MMG5_iare[ia][1]];
72 calold = pt->qual;
73
74 /* Store shell of ia in list, and associated pseudo polygon in pol */
75 (*ilist) = 0;
76 npol = 0;
77 list[(*ilist)] = 6*(int64_t)start+ia;
78 (*ilist)++;
79 adja = &mesh->adja[4*(start-1)+1];
80 adj = adja[MMG5_ifar[ia][0]]; // start travelling by face (ia,0)
81 ifac = adj%4;
82 piv = pt->v[MMG5_ifar[ia][1]];
83 pol[npol] = 4*start + MMG5_ifar[ia][1];
84 npol++;
85
86 /* Edge is on a boundary between two different domains */
87 if ( mesh->info.opnbdy )
88 if ( pt->xt && (mesh->xtetra[pt->xt].ftag[MMG5_ifar[ia][1]] & MG_BDY) )
89 return 0;
90
91 while ( adj ) {
92 adj /= 4;
93 if ( adj ==start ) break;
94
95 pt = &mesh->tetra[adj];
96 if ( pt->tag & MG_REQ ) return 0;
97
98 /* Edge is on a boundary between two different domains */
99 if ( pt->ref != refdom ) return 0;
100 else if ( mesh->info.opnbdy ) {
101 if ( pt->xt && (mesh->xtetra[pt->xt].ftag[ifac] & MG_BDY) ) return 0;
102 }
103
104 calold = MG_MIN(calold, pt->qual);
105
106 /* identification of edge number in tetra adj */
107 if ( !MMG3D_findEdge(mesh,pt,adj,na,nb,1,NULL,&i) ) return -1;
108
109 list[(*ilist)] = 6*(int64_t)adj +i;
110 (*ilist)++;
111 /* overflow */
112 if ( (*ilist) > MMG3D_LMAX-3 ) return 0;
113
114 /* set new triangle for travel */
115 adja = &mesh->adja[4*(adj-1)+1];
116 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
117 pol[npol] = 4*adj + MMG5_ifar[i][1];
118 npol++;
119 adj = adja[ MMG5_ifar[i][0] ];
120 piv = pt->v[ MMG5_ifar[i][1] ];
121 }
122 else {
123 assert(pt->v[ MMG5_ifar[i][1] ] == piv);
124 pol[npol] = 4*adj + MMG5_ifar[i][0];
125 npol++;
126 adj = adja[ MMG5_ifar[i][1] ];
127 piv = pt->v[ MMG5_ifar[i][0] ];
128 }
129 ifac = adj%4;
130 }
131
132 //CECILE : je vois pas pourquoi ca ameliore de faire ce test
133 //plus rapide mais du coup on elimine des swap...
134 //4/01/14 commentaire
135 // if ( calold*MMG3D_ALPHAD > 0.5 ) return 0;
136
137 /* Prevent swap of an external boundary edge */
138 if ( !adj ) return 0;
139
140 assert(npol == (*ilist)); // du coup, apres on pourra virer npol
141
142 /* Find a configuration that enhances the worst quality within the shell */
143 for (k=0; k<npol; k++) {
144 iel = pol[k] / 4;
145 ip = pol[k] % 4;
146 np = mesh->tetra[iel].v[ip];
147 calnew = 1.0;
148 ier = 1;
149
150 if ( mesh->info.fem ) {
151 /* Do not create internal edges between boundary points */
152 p0 = &mesh->point[np];
153 if ( p0->tag & MG_BDY ) {
154 /* One of the vertices of the pseudo polygon is boundary */
155 for (l=0; l<npol;l++) {
156 if ( k < npol-1 ) {
157 /* Skip the two elts of the pseudo polygon that contains p0 */
158 if ( l == k || l == k+1 ) continue;
159 }
160 else {
161 /* Skip the two elts of the pseudo polygon that contains p0 (for k==npol-1) */
162 if ( l == npol-1 || l == 0 ) continue;
163 }
164 iel = pol[l] / 4;
165 ip = pol[l] % 4;
166 pt = &mesh->tetra[iel];
167 p0 = &mesh->point[pt->v[ip]];
168 if ( p0->tag & MG_BDY ) {
169 /* Another vertex is boundary */
170 ier = 0;
171 break;
172 }
173 }
174 }
175 if ( !ier ) continue;
176 ier = 1;
177 }
178
179 for (l=0; l<(*ilist); l++) {
180 /* Do not consider tets of the shell of collapsed edge */
181 if ( k < npol-1 ) {
182 /* Skip the two elts of the pseudo polygon that contains np */
183 if ( l == k || l == k+1 ) continue;
184 }
185 else {
186 /* Skip the two elts of the pseudo polygon that contains np for the last polygon elt */
187 if ( l == npol-1 || l == 0 ) continue;
188 }
189 iel = list[l] / 6;
190 i = list[l] % 6;
191 pt = &mesh->tetra[iel];
192
193 /* Check that we will not insert a node that we will fail to collapse
194 * (recreation of an existing element) */
195 adja = &mesh->adja[4*(iel-1)+1];
196 adj = adja[MMG5_iare[i][0]]/4;
197 piv = adja[MMG5_iare[i][0]]%4;
198 if ( adj && mesh->tetra[adj].v[piv]==np ) {
199 ier = 0;
200 break;
201 }
202 adj = adja[MMG5_iare[i][1]]/4;
203 piv = adja[MMG5_iare[i][1]]%4;
204 if ( adj && mesh->tetra[adj].v[piv]==np ) {
205 ier = 0;
206 break;
207 }
208
209 /* Prevent from creating a tetra with 4 bdy vertices */
210 if ( mesh->point[np].tag & MG_BDY ) {
211 if ( ( mesh->point[pt->v[MMG5_ifar[i][0]]].tag & MG_BDY ) &&
212 ( mesh->point[pt->v[MMG5_ifar[i][1]]].tag & MG_BDY ) ) {
213 if ( ( mesh->point[pt->v[MMG5_iare[i][0]]].tag & MG_BDY ) ||
214 ( mesh->point[pt->v[MMG5_iare[i][1]]].tag & MG_BDY ) ) {
215 ier = 0;
216 break;
217 }
218 }
219 }
220
221 /* First tetra obtained from iel */
222 memcpy(pt0,pt,sizeof(MMG5_Tetra));
223 pt0->v[MMG5_iare[i][0]] = np;
224
225
226 if ( typchk==1 && met->size > 1 && met->m )
227 caltmp = MMG5_caltet33_ani(mesh,met,pt0);
228 else
229 caltmp = MMG5_orcal(mesh,met,0);
230
231 calnew = MG_MIN(calnew,caltmp);
232
233 ier = (calnew > crit*calold);
234 if ( !ier ) break;
235
236 /* Second tetra obtained from iel */
237 memcpy(pt0,pt,sizeof(MMG5_Tetra));
238 pt0->v[MMG5_iare[i][1]] = np;
239
240 if ( typchk==1 && met->size > 1 && met->m )
241 caltmp = MMG5_caltet33_ani(mesh,met,pt0);
242 else
243 caltmp = MMG5_orcal(mesh,met,0);
244
245 calnew = MG_MIN(calnew,caltmp);
246
247 ier = (calnew > crit*calold);
248 if ( !ier ) break;
249 }
250 if ( ier ) return pol[k];
251 }
252 return 0;
253}
254
271int MMG5_swpgen(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int nconf,int ilist,int64_t *list,
272 MMG3D_pPROctree PROctree, int8_t typchk) {
273 MMG5_pTetra pt;
274 MMG5_pPoint p0,p1;
275 int nball,ret,start;
276 MMG5_int src,iel,na,nb,np;
277 double m[3];
278 int8_t ia,ip,iq;
279 int ier;
280
281 iel = list[0] / 6;
282 ia = list[0] % 6;
283
284 pt = &mesh->tetra[iel];
285 na = pt->v[MMG5_iare[ia][0]];
286 nb = pt->v[MMG5_iare[ia][1]];
287 p0 = &mesh->point[na];
288 p1 = &mesh->point[nb];
289
290 /* Temporarily create midpoint at swapped edge */
291 m[0] = 0.5*(p0->c[0] + p1->c[0]);
292 m[1] = 0.5*(p0->c[1] + p1->c[1]);
293 m[2] = 0.5*(p0->c[2] + p1->c[2]);
294
295#ifdef USE_POINTMAP
296 src = mesh->point[na].src;
297#else
298 src = 1;
299#endif
300 np = MMG3D_newPt(mesh,m,0,src);
301 if(!np){
303 fprintf(stderr,"\n ## Error: %s: unable to allocate"
304 " a new point\n",__func__);
306 return -1
307 ,m,0,src);
308 }
309 assert ( met );
310 if ( met->m ) {
311 if ( typchk == 1 && (met->size>1) ) {
312 if ( MMG3D_intmet33_ani(mesh,met,iel,ia,np,0.5)<=0 ) return 0;
313 }
314 else {
315 if ( MMG5_intmet(mesh,met,iel,ia,np,0.5)<=0 ) return 0;
316 }
317 }
318
320 ret = 2*ilist + 0;
321 ier = MMG5_split1b(mesh,met,list,ret,np,0,typchk-1,0);
322
323 if ( ier < 0 ) {
324 fprintf(stderr,"\n ## Warning: %s: unable to swap internal edge.\n",
325 __func__);
326 return -1;
327 }
328 else if ( !ier ) {
329 MMG3D_delPt(mesh,np);
330 return 0;
331 }
332
334 start = nconf / 4;
335 iq = nconf % 4;
336
337 pt = &mesh->tetra[start];
338 for (ip=0; ip<4; ip++) {
339 if ( pt->v[ip] == np ) break;
340 }
341 assert(ip<4);
342
343 memset(list,0,(MMG3D_LMAX+2)*sizeof(MMG5_int));
344 nball = MMG5_boulevolp(mesh,start,ip,list);
345
346 ier = MMG5_colver(mesh,met,list,nball,iq,typchk);
347 if ( ier < 0 ) {
348 fprintf(stderr,"\n ## Warning: %s: unable to swap internal edge.\n",
349 __func__);
350 return -1;
351 }
352 else if ( ier ) {
354 }
355
356 /* Check for non convex situation */
357 assert ( ier && "Unable to collapse the point created during the internal swap");
358
359
360 return 1;
361}
int ier
MMG5_pMesh * mesh
int MMG5_boulevolp(MMG5_pMesh mesh, MMG5_int start, int ip, int64_t *list)
Definition: boulep_3d.c:54
int MMG3D_findEdge(MMG5_pMesh mesh, MMG5_pTetra pt, MMG5_int k, MMG5_int na, MMG5_int nb, int error, int8_t *mmgWarn, int8_t *ia)
Definition: boulep_3d.c:113
MMG5_int MMG5_colver(MMG5_pMesh mesh, MMG5_pSol met, int64_t *list, int ilist, int8_t indq, int8_t typchk)
Definition: colver_3d.c:1144
static double MMG5_orcal(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int iel)
int MMG3D_intmet33_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int8_t i, MMG5_int ip, double s)
Definition: intmet_3d.c:101
API headers for the mmg3d library.
#define MMG3D_LMAX
Definition: libmmg3d.h:58
MMG5_int MMG3D_newPt(MMG5_pMesh mesh, double c[3], int16_t tag, MMG5_int src)
Definition: zaldy_3d.c:39
int MMG5_split1b(MMG5_pMesh, MMG5_pSol, int64_t *, int, MMG5_int, int, int8_t, int8_t)
Definition: split_3d.c:617
void MMG3D_delPt(MMG5_pMesh mesh, MMG5_int ip)
Definition: zaldy_3d.c:80
double MMG5_caltet33_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTetra pt)
Definition: quality_3d.c:109
static const uint8_t MMG5_iare[6][2]
vertices of extremities of the edges of the tetra
static const uint8_t MMG5_ifar[6][2]
ifar[i][]: faces sharing the ith edge of the tetra
#define MMG3D_POINT_REALLOC(mesh, sol, ip, wantedGap, law, o, tag, src)
#define MG_REQ
#define MMG5_INCREASE_MEM_MESSAGE()
#define MG_MIN(a, b)
#define MG_BDY
int8_t fem
Definition: libmmgtypes.h:539
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_int * adja
Definition: libmmgtypes.h:624
double gap
Definition: libmmgtypes.h:608
MMG5_pTetra tetra
Definition: libmmgtypes.h:643
MMG5_pxTetra xtetra
Definition: libmmgtypes.h:644
Structure to store points of a MMG mesh.
Definition: libmmgtypes.h:270
int16_t tag
Definition: libmmgtypes.h:284
double c[3]
Definition: libmmgtypes.h:271
double * m
Definition: libmmgtypes.h:671
MMG5_int v[4]
Definition: libmmgtypes.h:403
MMG5_int xt
Definition: libmmgtypes.h:407
MMG5_int ref
Definition: libmmgtypes.h:404
double qual
Definition: libmmgtypes.h:402
int16_t tag
Definition: libmmgtypes.h:410
int16_t ftag[4]
Definition: libmmgtypes.h:423
MMG5_int MMG5_chkswpgen(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int start, int ia, int *ilist, int64_t *list, double crit, int8_t typchk)
Definition: swapgen_3d.c:57
int MMG5_swpgen(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int nconf, int ilist, int64_t *list, MMG3D_pPROctree PROctree, int8_t typchk)
Definition: swapgen_3d.c:271