Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
swapar_s.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
36#include "libmmgs_private.h"
37#include "mmgsexterns_private.h"
38#include "mmgexterns_private.h"
40
58int chkswp(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int k,int i,int8_t typchk,
59 double (*MMGS_lenEdg)(MMG5_pMesh,MMG5_pSol,MMG5_int ,MMG5_int,int8_t),
60 double (*MMGS_caltri)(MMG5_pMesh,MMG5_pSol,MMG5_pTria)) {
61 MMG5_pTria pt,pt0,pt1;
62 MMG5_pPoint p[3],q;
63 MMG5_pPar par;
64 double np[3][3],nq[3],*nr1,*nr2,nt[3],ps,ps2,*n1,*n2,dd,c1[3],c2[3],hausd;
65 double cosn1,cosn2,calnat,calchg,cal1,cal2,cosnat,coschg,ux,uy,uz,ll,loni,lona;
66 MMG5_int *adja,j,kk,l,ip0,ip1,ip2,iq;
67 int isloc;
68 int8_t ii,i1,i2,jj;
69
70 pt0 = &mesh->tria[0];
71 pt = &mesh->tria[k];
72 i1 = MMG5_inxt2[i];
73 i2 = MMG5_iprv2[i];
74 if ( MG_EDG(pt->tag[i]) || MS_SIN(pt->tag[i]) ) return 0;
75 else if ( MS_SIN(pt->tag[i1]) ) return 0;
76
77 ip0 = pt->v[i];
78 ip1 = pt->v[i1];
79 ip2 = pt->v[i2];
80 p[0] = &mesh->point[ip0];
81 p[1] = &mesh->point[ip1];
82 p[2] = &mesh->point[ip2];
83
84 adja = &mesh->adja[3*(k-1)+1];
85 if ( !adja[i] ) return 0;
86
87 kk = adja[i] / 3;
88 ii = adja[i] % 3;
89 jj = MMG5_inxt2[ii];
90 pt1 = &mesh->tria[kk];
91 if ( MS_SIN(pt1->tag[jj]) ) return 0;
92
93 iq = pt1->v[ii];
94 q = &mesh->point[iq];
95
96 /* local hausdorff for triangle */
97 hausd = mesh->info.hausd;
98 isloc = 0;
99 for (l=0; l<mesh->info.npar; l++) {
100 par = &mesh->info.par[l];
101 if ( ((par->elt == MMG5_Triangle) &&
102 ( (pt->ref == par->ref) || (pt1->ref == par->ref) )) /* ||
103 ( (par->elt == MMG5_Vertex) &&
104 ((p[1]->ref == par->ref ) || (p[2]->ref == par->ref)) ) */ ) {
105 if ( !isloc ) {
106 hausd = par->hausd;
107 isloc = 1;
108 }
109 else {
110 // take the minimum value between the two local hausdorff number asked
111 // by the user.
112 hausd = MG_MIN(hausd,par->hausd);
113 }
114 }
115 }
116
117 /* check length */
118 if ( MMGS_lenEdg ) {
119 loni = MMGS_lenEdg(mesh,met,ip1,ip2,0);
120 lona = MMGS_lenEdg(mesh,met,ip0,iq,0);
121 if ( loni > 1.0 ) loni = MG_MIN(1.0 / loni,MMGS_LSHRT);
122 if ( lona > 1.0 ) lona = 1.0 / lona;
123 if ( lona < loni || !loni ) return 0;
124 }
125
126 /* check non convexity */
127 MMG5_norpts(mesh,ip0,ip1,iq,c1);
128 MMG5_norpts(mesh,ip0,iq,ip2,c2);
129 ps = c1[0]*c2[0] + c1[1]*c2[1] + c1[2]*c2[2];
130 if ( ps < MMG5_ANGEDG ) return 0;
131
132 /* normal recovery at points p[0],p[1],p[2],q */
133 for (j=0; j<3; j++) {
134 if ( MS_SIN(p[j]->tag) ) {
135 MMG5_nortri(mesh,pt,np[j]);
136 }
137 else if ( MG_EDG(p[j]->tag) ) {
138 MMG5_nortri(mesh,pt,nt);
139 nr1 = &mesh->xpoint[p[j]->xp].n1[0];
140 nr2 = &mesh->xpoint[p[j]->xp].n2[0];
141 ps = nr1[0]*nt[0] + nr1[1]*nt[1] + nr1[2]*nt[2];
142 ps2 = nr2[0]*nt[0] + nr2[1]*nt[1] + nr2[2]*nt[2];
143 if ( fabs(ps) > fabs(ps2) )
144 memcpy(&np[j],nr1,3*sizeof(double));
145 else
146 memcpy(&np[j],nr2,3*sizeof(double));
147 }
148 else
149 memcpy(&np[j],p[j]->n,3*sizeof(double));
150 }
151
152 if ( MS_SIN(q->tag) ) {
153 MMG5_nortri(mesh,pt,nq);
154 }
155 else if ( MG_EDG(q->tag) ) {
156 MMG5_nortri(mesh,pt,nt);
157 nr1 = &mesh->xpoint[q->xp].n1[0];
158 nr2 = &mesh->xpoint[q->xp].n2[0];
159 ps = nr1[0]*nt[0] + nr1[1]*nt[1] + nr1[2]*nt[2];
160 ps2 = nr2[0]*nt[0] + nr2[1]*nt[1] + nr2[2]*nt[2];
161 if ( fabs(ps) > fabs(ps2) )
162 memcpy(&nq,nr1,3*sizeof(double));
163 else
164 memcpy(&nq,nr2,3*sizeof(double));
165 }
166 else
167 memcpy(&nq,q->n,3*sizeof(double));
168
169 /* Estimate of the Hausdorff distance between approximation and underlying surface
170 when using the 'natural' edge [i1,i2] */
171 ux = p[2]->c[0] - p[1]->c[0];
172 uy = p[2]->c[1] - p[1]->c[1];
173 uz = p[2]->c[2] - p[1]->c[2];
174
175 ll = ux*ux + uy*uy + uz*uz;
176 if ( ll < MMG5_EPS ) return 0; /* no change for short edge */
177
178 n1 = np[1];
179 n2 = np[2];
180
181 ps = ux*n1[0] + uy*n1[1] + uz*n1[2];
182 c1[0] = (2.0*p[1]->c[0] + p[2]->c[0] - ps*n1[0]) / 3.0 - p[1]->c[0];
183 c1[1] = (2.0*p[1]->c[1] + p[2]->c[1] - ps*n1[1]) / 3.0 - p[1]->c[1];
184 c1[2] = (2.0*p[1]->c[2] + p[2]->c[2] - ps*n1[2]) / 3.0 - p[1]->c[2];
185
186 ps = -(ux*n2[0] + uy*n2[1] + uz*n2[2]);
187 c2[0] = (2.0*p[2]->c[0] + p[1]->c[0] - ps*n2[0]) / 3.0 - p[2]->c[0];
188 c2[1] = (2.0*p[2]->c[1] + p[1]->c[1] - ps*n2[1]) / 3.0 - p[2]->c[1];
189 c2[2] = (2.0*p[2]->c[2] + p[1]->c[2] - ps*n2[2]) / 3.0 - p[2]->c[2];
190
191 /* squared cosines */
192 ps = c1[0]*ux + c1[1]*uy + c1[2]*uz;
193 ps *= ps;
194 dd = c1[0]*c1[0] + c1[1]*c1[1] + c1[2]*c1[2];
195 cosn1 = ps / (dd*ll);
196 cosn1 *= (1.0-cosn1);
197 cosn1 *= (0.25*ll);
198
199 ps = -c2[0]*ux - c2[1]*uy - c2[2]*uz;
200 ps *= ps;
201 dd = c2[0]*c2[0]+c2[1]*c2[1]+c2[2]*c2[2];
202 cosn2 = ps / (dd*ll);
203 cosn2 *= (1.0-cosn2);
204 cosn2 *= (0.25*ll);
205
206 cosnat = MG_MAX(fabs(cosn1),fabs(cosn2));
207 cosnat = cosnat < MMG5_EPS ? 0.0 : cosnat;
208
209 /* Estimate of the Hausdorff distance between approximation and underlying surface
210 when using the 'swapped' edge [i0,q] */
211 ux = q->c[0] - p[0]->c[0];
212 uy = q->c[1] - p[0]->c[1];
213 uz = q->c[2] - p[0]->c[2];
214
215 ll = ux*ux + uy*uy + uz*uz;
216 if ( ll < MMG5_EPS ) return 0;
217
218 n1 = np[0];
219 n2 = nq;
220
221 ps = ux*n1[0] + uy*n1[1] + uz*n1[2];
222 c1[0] = (2.0*p[0]->c[0] + q->c[0] - ps*n1[0]) / 3.0 - p[0]->c[0];
223 c1[1] = (2.0*p[0]->c[1] + q->c[1] - ps*n1[1]) / 3.0 - p[0]->c[1];
224 c1[2] = (2.0*p[0]->c[2] + q->c[2] - ps*n1[2]) / 3.0 - p[0]->c[2];
225
226 ps = -(ux*n2[0] + uy*n2[1] + uz*n2[2]);
227 c2[0] = (2.0*q->c[0] + p[0]->c[0] - ps*n2[0]) / 3.0 - q->c[0];
228 c2[1] = (2.0*q->c[1] + p[0]->c[1] - ps*n2[1]) / 3.0 - q->c[1];
229 c2[2] = (2.0*q->c[2] + p[0]->c[2] - ps*n2[2]) / 3.0 - q->c[2];
230
231 /* squared cosines */
232 ps = c1[0]*ux + c1[1]*uy + c1[2]*uz;
233 ps *= ps;
234 dd = c1[0]*c1[0] + c1[1]*c1[1] + c1[2]*c1[2];
235 cosn1 = ps / (dd*ll);
236 cosn1 *= (1.0-cosn1);
237 cosn1 *= (0.25*ll);
238
239 ps = -c2[0]*ux - c2[1]*uy - c2[2]*uz;
240 ps *= ps;
241 dd = c2[0]*c2[0]+c2[1]*c2[1]+c2[2]*c2[2];
242 cosn2 = ps / (dd*ll);
243 cosn2 *= (1.0-cosn2);
244 cosn2 *= (0.25*ll);
245
246 coschg = MG_MAX(fabs(cosn1),fabs(cosn2));
247 coschg = coschg < MMG5_EPS ? 0.0 : coschg;
248
249 /* swap if Hausdorff contribution of the swapped edge is less than existing one */
250 if ( coschg > hausd*hausd ) return 0;
251
252 if ( typchk == 2 && met->m ) {
253 /* initial quality */
254 pt0->v[0]= ip0; pt0->v[1]= ip1; pt0->v[2]= ip2;
255 pt0->tag[0] = pt->tag[i];
256 pt0->tag[1] = pt->tag[i1];
257 pt0->tag[2] = pt->tag[i2];
258 cal1 = MMG5_calelt(mesh,met,pt0);
259
260 /* BUG ??? pt1 should be here !*/
261 pt0->v[0]= ip1; pt0->v[1]= iq; pt0->v[2]= ip2;
262 pt0->tag[0] = pt->tag[i1];
263 pt0->tag[1] = pt->tag[ii];
264 pt0->tag[2] = pt->tag[i2];
265 cal2 = MMG5_calelt(mesh,met,pt0);
266
267 calnat = MG_MIN(cal1,cal2);
268 assert(calnat > 0.);
269
270 /* quality after swap */
271 pt0->v[0]= ip0; pt0->v[1]= ip1; pt0->v[2]= iq;
272 pt0->tag[0] = pt->tag[i];
273 pt0->tag[1] = pt->tag[i1];
274 pt0->tag[2] = pt->tag[ii];
275 cal1 = MMG5_calelt(mesh,met,pt0);
276
277 pt0->v[0]= ip0; pt0->v[1]= iq; pt0->v[2]= ip2;
278 pt0->tag[0] = pt->tag[i];
279 pt0->tag[1] = pt->tag[ii];
280 pt0->tag[2] = pt->tag[i2];
281 cal2 = MMG5_calelt(mesh,met,pt0);
282
283 calchg = MG_MIN(cal1,cal2);
284 }
285 else {
286 pt0->v[0]= ip0; pt0->v[1]= ip1; pt0->v[2]= ip2;
287 cal1 = MMGS_caltri(mesh,met,pt0);
288 pt0->v[0]= ip1; pt0->v[1]= iq; pt0->v[2]= ip2;
289 cal2 = MMGS_caltri(mesh,met,pt0);
290 calnat = MG_MIN(cal1,cal2);
291 pt0->v[0]= ip0; pt0->v[1]= ip1; pt0->v[2]= iq;
292 cal1 = MMGS_caltri(mesh,met,pt0);
293 pt0->v[0]= ip0; pt0->v[1]= iq; pt0->v[2]= ip2;
294 cal2 = MMGS_caltri(mesh,met,pt0);
295 calchg = MG_MIN(cal1,cal2);
296 }
297
298 /* if the quality is very bad, don't degrade it, even to improve the surface
299 * approx. */
300 if ( calchg < MMG5_EPS && calnat >= calchg ) return 0;
301
302 /* else we can degrade the quality to improve the surface approx. */
303 if ( coschg < hausd*hausd && cosnat > hausd*hausd ) return 1;
304
305 return calchg > 1.01 * calnat;
306}
307
318int swapar(MMG5_pMesh mesh,MMG5_int k,int i) {
319 MMG5_pTria pt,pt1;
320 MMG5_int *adja,adj,k11,k21,ip1,ip2,i2save,j2save;
321 int8_t i1,i2,j,jj,j2,v11,v21;
322
323 pt = &mesh->tria[k];
324 if ( MG_EDG(pt->tag[i]) || MS_SIN(pt->tag[i]) ) return 0;
325
326 adja = &mesh->adja[3*(k-1)+1];
327 assert(adja[i]);
328
329 adj = adja[i] / 3;
330 j = adja[i] % 3;
331 pt1 = &mesh->tria[adj];
332
333 /* simulation */
334 i1 = MMG5_inxt2[i];
335 i2 = MMG5_iprv2[i];
336
337 /* update structure */
338 k11 = adja[i1] / 3;
339 v11 = adja[i1] % 3;
340 if ( k11 < 1 ) return 0;
341 ip1 = mesh->tria[k11].v[v11];
342
343 adja = &mesh->adja[3*(adj-1)+1];
344 jj = MMG5_inxt2[j];
345 j2 = MMG5_iprv2[j];
346 k21 = adja[jj] / 3;
347 v21 = adja[jj] % 3;
348 if ( k21 < 1 ) return 0;
349 ip2 = mesh->tria[k21].v[v21];
350
351 i2save = pt->v[i2];
352 pt->v[i2] = pt1->v[j];
353 j2save = pt1->v[j2];
354 pt1->v[j2] = pt->v[i];
355
356 /* Check that the edge swap doesn't create a lost face. Revert the swap in
357 * this case */
358 if ( pt->v[i] == ip2 ) {
359 pt->v[i2] = i2save;
360 pt1->v[j2] = j2save;
361 return 0;
362 }
363
364 if ( pt1->v[j] == ip1 ) {
365 pt->v[i2] = i2save;
366 pt1->v[j2] = j2save;
367 return 0;
368 }
369
370
371 /* update info */
372 pt->tag[i] = pt1->tag[jj];
373 pt->edg[i] = pt1->edg[jj];
374 pt->base = mesh->base;
375 pt1->tag[j] = pt->tag[i1];
376 pt1->edg[j] = pt->edg[i1];
377 pt->tag[i1] = 0;
378 pt->edg[i1] = 0;
379 pt1->tag[jj] = 0;
380 pt1->edg[jj] = 0;
381 pt1->base = mesh->base;
382
383 /* update adjacent */
384 mesh->adja[3*(k-1)+1+i] = 3*k21+v21;
385 mesh->adja[3*(k21-1)+1+v21] = 3*k+i;
386 mesh->adja[3*(k-1)+1+i1] = 3*adj+jj;
387 mesh->adja[3*(adj-1)+1+jj] = 3*k+i1;
388 mesh->adja[3*(k11-1)+1+v11] = 3*adj+j;
389 mesh->adja[3*(adj-1)+1+j] = 3*k11+v11;
390
391 return 1;
392}
MMG5_pMesh * mesh
#define MMG5_EPS
#define MMGS_LSHRT
#define MS_SIN(tag)
@ MMG5_Triangle
Definition: libmmgtypes.h:226
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
static const uint8_t MMG5_inxt2[6]
int MMG5_nortri(MMG5_pMesh mesh, MMG5_pTria pt, double *n)
Definition: tools.c:209
#define MMG5_ANGEDG
int MMG5_norpts(MMG5_pMesh, MMG5_int, MMG5_int, MMG5_int, double *)
Definition: tools.c:183
MMG5_pPar par
Definition: libmmgtypes.h:517
double hausd
Definition: libmmgtypes.h:518
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
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:642
MMG5_int base
Definition: libmmgtypes.h:616
MMG5_pTria tria
Definition: libmmgtypes.h:647
double hausd
Definition: libmmgtypes.h:260
MMG5_int ref
Definition: libmmgtypes.h:261
int8_t elt
Definition: libmmgtypes.h:262
Structure to store points of a MMG mesh.
Definition: libmmgtypes.h:270
double n[3]
Definition: libmmgtypes.h:272
int16_t tag
Definition: libmmgtypes.h:284
double c[3]
Definition: libmmgtypes.h:271
MMG5_int xp
Definition: libmmgtypes.h:279
double * m
Definition: libmmgtypes.h:671
MMG5_int edg[3]
Definition: libmmgtypes.h:339
int16_t tag[3]
Definition: libmmgtypes.h:342
MMG5_int ref
Definition: libmmgtypes.h:335
MMG5_int base
Definition: libmmgtypes.h:336
MMG5_int v[3]
Definition: libmmgtypes.h:334
double n2[3]
Definition: libmmgtypes.h:295
double n1[3]
Definition: libmmgtypes.h:295
int chkswp(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int i, int8_t typchk, double(*MMGS_lenEdg)(MMG5_pMesh, MMG5_pSol, MMG5_int, MMG5_int, int8_t), double(*MMGS_caltri)(MMG5_pMesh, MMG5_pSol, MMG5_pTria))
Definition: swapar_s.c:58
int swapar(MMG5_pMesh mesh, MMG5_int k, int i)
Definition: swapar_s.c:318