Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
anisomovpt_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 "mmgexterns_private.h"
38
49int movintpt_ani(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int *list,int ilist) {
50 MMG5_pTria pt,pt0;
51 MMG5_pPoint p0,ppt0;
52 MMG5_Bezier pb;
53 double r[3][3],lispoi[3*MMG5_TRIA_LMAX+1],*m0;//,m[6],mo[6];
54 double gv[2],area,detloc,step,lambda[3],o[3],no[3],to[3],uv[2];
55 double calold,calnew,caltmp;
56 MMG5_int k,iel,kel,nump,nbeg,nend;
57 int8_t i0,i1,i2,ier;
58 static int warn=0;
59 static int8_t mmgErr0=0,mmgErr1=0;
60
61 step = 0.1;
62
63 /* Make sure ball of point is closed */
64 iel = list[0] / 3;
65 i0 = list[0] % 3;
66 i1 = MMG5_inxt2[i0];
67
68 pt = &mesh->tria[iel];
69 nump = pt->v[i0];
70 nbeg = pt->v[i1];
71 p0 = &mesh->point[nump];
72 m0 = &met->m[6*nump];
73 assert( !p0->tag );
74
75 iel = list[ilist-1] / 3;
76 i0 = list[ilist-1] % 3;
77 i2 = MMG5_iprv2[i0];
78
79 pt = &mesh->tria[iel];
80 nend = pt->v[i2];
81 if ( nbeg != nend ) return 0;
82
83 /* Rotation of the ball of p0 */
84 if ( !MMGS_surfballRotation(mesh,p0,list,ilist,r,lispoi,p0->n) ) {
85 return 0;
86 }
87
90 gv[0] = 0.0;
91 gv[1] = 0.0;
92
93 for (k=0; k<ilist; k++) {
94 iel = list[k] / 3;
95 pt = &mesh->tria[iel];
96 if ( !MMG5_bezierCP(mesh,pt,&pb,1) ) return 0;
97
98 /* Compute integral of sqrt(T^J(xi) M(P(xi)) J(xi)) * P(xi) over the triangle */
99 if ( !MMG5_elementWeight(mesh,met,pt,p0,&pb,r,gv) ) {
100 if ( !warn ) {
101 ++warn;
102 fprintf(stderr,"\n ## Warning: %s: unable to compute optimal position for at least"
103 " 1 point.\n",__func__ );
104 }
105 return 0;
106 }
107 }
108
109 /* At this point : gv = - gradient of V = direction to follow */
111 area = lispoi[1]*gv[1] - lispoi[2]*gv[0];
112 kel = 0;
113 if ( area >= 0.0 ) {
114 for (k=0; k<ilist; k++) {
115 detloc = gv[0]*lispoi[3*(k+1)+2] - gv[1]*lispoi[3*(k+1)+1]; /*orientation with respect to p2 */
116 if ( detloc >= 0.0 ) {
117 kel = k;
118 break;
119 }
120 }
121 if ( k == ilist ) return 0;
122 }
123 else {
124 for (k=ilist-1; k>=0; k--) {
125 detloc = lispoi[3*k+1]*gv[1] - lispoi[3*k+2]*gv[0]; //orientation with respect to p2
126 if ( detloc >= 0.0 ) {
127 kel = k;
128 break;
129 }
130 }
131 if ( k == -1 ) return 0;
132 }
133
134 /* Sizing of time step : make sure point does not go out corresponding triangle. */
135 area = - gv[1]*(lispoi[3*(kel+1)+1] - lispoi[3*(kel)+1]) \
136 + gv[0]*(lispoi[3*(kel+1)+2] - lispoi[3*(kel)+2]);
137 if ( fabs(area) < MMG5_EPSD2 ) return 0;
138 area = 1.0 / area;
139 step *= area;
140
141 area = lispoi[3*(kel)+1]*(lispoi[3*(kel+1)+2] - lispoi[3*(kel)+2]) \
142 - lispoi[3*(kel)+2 ]*(lispoi[3*(kel+1)+1] - lispoi[3*(kel)+1]);
143 step *= area;
144 step = fabs(step);
145 gv[0] *= step;
146 gv[1] *= step;
147
148 /* Computation of the barycentric coordinates of the new point in the corresponding triangle. */
149 area = lispoi[3*kel+1]*lispoi[3*(kel+1)+2] - lispoi[3*kel+2]*lispoi[3*(kel+1)+1];
150 if ( area < MMG5_EPSD2 ) return 0;
151 area = 1.0 / area;
152 lambda[1] = lispoi[3*(kel+1)+2]*gv[0] - lispoi[3*(kel+1)+1]*gv[1];
153 lambda[2] = -lispoi[3*(kel)+2]*gv[0] + lispoi[3*(kel)+1]*gv[1];
154 lambda[1]*= (area);
155 lambda[2]*= (area);
156 lambda[0] = 1.0 - lambda[1] - lambda[2];
157
159 iel = list[kel] / 3;
160 i0 = list[kel] % 3;
161 pt = &mesh->tria[iel];
162
163 ier = MMG5_bezierCP(mesh,pt,&pb,1);
164 if ( !ier ) {
165 if( !mmgErr0 ) {
166 mmgErr0 = 1;
167 fprintf(stderr,"\n ## Warning: %s: function MMG5_bezierCP return 0.\n",
168 __func__);
169 }
170 return 0;
171 }
172
173 /* Now, for Bezier interpolation, one should identify which of i,i1,i2 is 0,1,2
174 recall uv[0] = barycentric coord associated to pt->v[1], uv[1] associated to pt->v[2] */
175 if ( i0 == 0 ) {
176 uv[0] = lambda[1];
177 uv[1] = lambda[2];
178 }
179 else if ( i0 == 1 ) {
180 uv[0] = lambda[0];
181 uv[1] = lambda[1];
182 }
183 else{
184 uv[0] = lambda[2];
185 uv[1] = lambda[0];
186 }
187
188 ier = MMGS_bezierInt(&pb,uv,o,no,to);
189 if ( !ier ) {
190 if( !mmgErr1 ) {
191 mmgErr1 = 1;
192 fprintf(stderr," ## Warning: %s: function MMGS_bezierInt return 0.\n",
193 __func__);
194 }
195 return 0;
196 }
197
198 /* Second test : check whether geometric approximation has not been too much degraded */
199 ppt0 = &mesh->point[0];
200 ppt0->c[0] = o[0];
201 ppt0->c[1] = o[1];
202 ppt0->c[2] = o[2];
203
204 ppt0->n[0] = no[0];
205 ppt0->n[1] = no[1];
206 ppt0->n[2] = no[2];
207 ppt0->tag = 0;
208
209 // parallel transport of metric at p0 to new point
210 MMG5_paratmet(p0->c,p0->n,m0,o,no,&met->m[0]);
211
212 calold = calnew = DBL_MAX;
213 for (k= 0; k<ilist; k++) {
214 iel = list[k] / 3;
215 i0 = list[k] % 3;
216 pt = &mesh->tria[iel];
217 pt0 = &mesh->tria[0];
218 memcpy(pt0,pt,sizeof(MMG5_Tria));
219 pt0->v[i0] = 0;
220
221 caltmp = caleltsig_ani(mesh,met,iel);
222 calold = MG_MIN(calold,caltmp);
223 caltmp = caleltsig_ani(mesh,met,0);
224 if ( caltmp < MMG5_EPSD2 ) {
225 /* We don't check the input triangle qualities, thus we may have a very
226 * bad triangle in our mesh */
227 return 0;
228 }
229 calnew = MG_MIN(calnew,caltmp);
230
231 if ( calold < MMG5_EPSOK && calnew <= calold ) return 0;
232 else if (calnew < MMG5_EPSOK) return 0;
233 else if ( calnew < 0.3*calold ) return 0;
234 /* if ( chkedg(mesh,0) ) return 0; */
235 }
236
237 /* Finally, update coordinates and normals of point, if new position is accepted :*/
238 p0->c[0] = o[0];
239 p0->c[1] = o[1];
240 p0->c[2] = o[2];
241
242 p0->n[0] = no[0];
243 p0->n[1] = no[1];
244 p0->n[2] = no[2];
245
246 memcpy(m0,&met->m[0],6*sizeof(double));
247
248 return 1;
249}
250
251/* Compute movement of a ref, or ridge point whose ball is passed */
252int movridpt_ani(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int *list,int ilist) {
253 MMG5_pTria pt,pt0;
254 MMG5_pPoint p0,p1,p2,ppt0;
255 MMG5_pxPoint go;
256 double *m0,*m00,step,l1old,l2old,ll1old,ll2old;
257 double lam0,lam1,lam2,o[3],nn1[3],nn2[3],to[3],mo[6];
258 double l1new,l2new,calold,calnew;
259 MMG5_int it,it1,it2,ip,ip0,ip1,ip2,k,iel;
260 int8_t voy1,voy2,isrid,isrid1,isrid2,i0,i1,i2;
261 static int8_t mmgWarn0 = 0;
262
263 step = 0.2;
264 isrid1 = isrid2 = 0;
265 it1 = it2 = 0;
266 ip1 = ip2 = 0;
267 voy1 = voy2 = 0;
268
269 /* First step : make sure 2 ridge edges pass through point, and recoved them,
270 along with neighbouring triangles */
271 for (k=0; k<ilist; k++) {
272 iel = list[k] / 3;
273 i0 = list[k] % 3;
274 i1 = MMG5_inxt2[i0];
275 i2 = MMG5_inxt2[i1];
276 pt = &mesh->tria[iel];
277
278 if ( MG_EDG(pt->tag[i1]) ) {
279 if ( !it1 ) {
280 it1 = iel;
281 ip1 = pt->v[i2]; // edge(i1) = (p0p2)
282 voy1 = i1;
283 if ( pt->tag[i1] & MG_GEO ) isrid1 = 1;
284 }
285 else if ( it1 && !it2 ) {
286 if ( ip1 != pt->v[i2] ) {
287 it2 = iel;
288 ip2 = pt->v[i2]; // edge(i1) = (p0p2)
289 voy2 = i1;
290 if ( pt->tag[i1] & MG_GEO ) isrid2 = 1;
291 }
292 }
293 else if ( it1 && it2 && (pt->v[i2] != ip1) && (pt->v[i2] != ip2) ) {
294 if ( !mmgWarn0 ) {
295 mmgWarn0 = 1;
296 fprintf(stderr,"\n ## Warning: %s: at least 1 point at the"
297 " intersection of 3 ridge edges\n",__func__);
298 }
299 return 0;
300 }
301 }
302
303 if ( MG_EDG(pt->tag[i2]) ) {
304 if ( !it1 ) {
305 it1 = iel;
306 ip1 = pt->v[i1]; // edge(i2) = (p0p1)
307 voy1 = i2;
308 if ( pt->tag[i2] & MG_GEO ) isrid1 = 1;
309 }
310 else if ( it1 && !it2 ) {
311 if ( ip1 != pt->v[i1] ) {
312 it2 = iel;
313 ip2 = pt->v[i1]; // edge(i1) = (p0p2)
314 voy2 = i2;
315 if ( pt->tag[i2] & MG_GEO ) isrid2 = 1;
316 }
317 }
318 else if ( it1 && it2 && (pt->v[i1] != ip1) && (pt->v[i1] != ip2) ) {
319 if ( !mmgWarn0 ) {
320 mmgWarn0 = 1;
321 fprintf(stderr,"\n ## Warning: %s: at least 1 point at the"
322 " intersection of 3 ridge edges\n",__func__);
323 }
324 return 0;
325 }
326 }
327 }
328
329 /* Second step : compute lengths of edges (p0p1),(p0p2) */
330 iel = list[0] / 3;
331 i0 = list[0] % 3;
332 pt = &mesh->tria[iel];
333 ip0 = pt->v[i0];
334 p0 = &mesh->point[ip0];
335 p1 = &mesh->point[ip1];
336 p2 = &mesh->point[ip2];
337 m0 = &met->m[6*ip0];
338
339 l1old = MMG5_lenSurfEdg(mesh,met,ip0,ip1,1);
340 l2old = MMG5_lenSurfEdg(mesh,met,ip0,ip2,1);
341
342 if ( (!l1old) || (!l2old) ) return 0;
343
344 if ( l1old < l2old ) { //move towards p2
345 ip = ip2;
346 isrid = isrid2;
347 it = it2;
348 }
349 else {
350 ip = ip1;
351 isrid = isrid1;
352 it = it1;
353 }
354
355 /* Third step : infer arc length of displacement, parameterized over edges */
356 if ( !MMGS_paramDisp ( mesh,it,isrid,ip0,ip,step,o) ) {
357 return 0;
358 }
359
360 /* check whether proposed move is admissible uner consideration of distances */
361 /* Normal and tangent vector updates */
362 lam0 = (1.0-step)*(1.0-step);
363 lam1 = 2.0*step*(1.0-step);
364 lam2 = step*step;
365
366 /* Move is made towards p2 */
367 ll1old = l1old*l1old;
368 ll2old = l2old*l2old;
369
370 if ( l2old > l1old ) {
371 if ( !MMGS_moveTowardPoint(mesh,p0,p2,ll2old,lam0,lam1,lam2,nn1,nn2,to) ) {
372 return 0;
373 }
374
375 /* Interpolation of metric between ip0 and ip2 */
376 if ( isrid ) {
377 if(!MMG5_intridmet(mesh,met,mesh->tria[it2].v[MMG5_inxt2[voy2]],
378 mesh->tria[it2].v[MMG5_iprv2[voy2]],(1.0-step),nn1,mo))
379 return 0;
380 }
381 else {
382 if ( !MMG5_paratmet(p0->c,p0->n,m0,o,nn1,mo) ) return 0;
383 }
384 }
385
386 /* Move along p1 */
387 else {
388 if ( !MMGS_moveTowardPoint(mesh,p0,p1,ll1old,lam0,lam1,lam2,nn1,nn2,to) ) {
389 return 0;
390 }
391
392 /* Interpolation of metric between ip0 and ip1 */
393 if ( isrid ) {
394 MMG5_intridmet(mesh,met,mesh->tria[it1].v[MMG5_inxt2[voy1]],
395 mesh->tria[it1].v[MMG5_iprv2[voy1]],(1.0-step),nn1,mo);
396 }
397 else {
398 if ( !MMG5_paratmet(p0->c,p0->n,m0,o,nn1,mo) ) return 0;
399 }
400 }
401
402 /* Check proposed motion */
403 ppt0 = &mesh->point[0];
404 ppt0->xp = 0;
405 ppt0->tag = p0->tag;
406
407 go = &mesh->xpoint[0];
408 go->n1[0] = nn1[0];
409 go->n1[1] = nn1[1];
410 go->n1[2] = nn1[2];
411
412 if ( isrid ) {
413 go->n2[0] = nn2[0];
414 go->n2[1] = nn2[1];
415 go->n2[2] = nn2[2];
416 }
417
418 ppt0->c[0] = o[0];
419 ppt0->c[1] = o[1];
420 ppt0->c[2] = o[2];
421
422 ppt0->n[0] = to[0];
423 ppt0->n[1] = to[1];
424 ppt0->n[2] = to[2];
425
426 m00 = &met->m[0];
427 memcpy(m00,mo,6*sizeof(double));
428
429 /* Check whether proposed move is admissible under consideration of distances */
430 l1new = MMG5_lenSurfEdg(mesh,met,0,ip1,1);
431 l2new = MMG5_lenSurfEdg(mesh,met,0,ip2,1);
432
433 if ( (!l1new) || (!l2new) ) return 0;
434
435 if ( fabs(l2new -l1new) >= fabs(l2old -l1old) ) {
436 ppt0->tag = 0;
437 return 0;
438 }
439
440 for (k=0; k<ilist; k++) {
441 iel = list[k] / 3;
442 i0 = list[k] % 3;
443 pt = &mesh->tria[iel];
444 pt0 = &mesh->tria[0];
445 memcpy(pt0,pt,sizeof(MMG5_Tria));
446 pt0->v[i0] = 0;
447
448 calold = caleltsig_ani(mesh,met,iel);
449 calnew = caleltsig_ani(mesh,met,0);
450 if ( (calnew < 0.001) && (calnew<calold) ) {
451 ppt0->tag = 0;
452 return 0;
453 }
454 else if ( calnew < 0.3*calold ) {
455 ppt0->tag = 0;
456 return 0;
457 }
458 /* if ( chkedg(mesh,0) ) return 0;*/
459 }
460
461 /* Coordinates, normals, tangents update */
462 p0->c[0] = o[0];
463 p0->c[1] = o[1];
464 p0->c[2] = o[2];
465
466 mesh->xpoint[p0->xp].n1[0] = nn1[0];
467 mesh->xpoint[p0->xp].n1[1] = nn1[1];
468 mesh->xpoint[p0->xp].n1[2] = nn1[2];
469
470 if ( isrid ) {
471 mesh->xpoint[p0->xp].n2[0] = nn2[0];
472 mesh->xpoint[p0->xp].n2[1] = nn2[1];
473 mesh->xpoint[p0->xp].n2[2] = nn2[2];
474 }
475
476 p0->n[0] = to[0];
477 p0->n[1] = to[1];
478 p0->n[2] = to[2];
479 memcpy(m0,mo,6*sizeof(double));
480
481 return 1;
482}
int ier
MMG5_pMesh * mesh
int MMG5_elementWeight(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria pt, MMG5_pPoint p0, MMG5_Bezier *pb, double r[3][3], double gv[2])
Definition: anisomovpt.c:53
int movintpt_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *list, int ilist)
Definition: anisomovpt_s.c:49
int movridpt_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *list, int ilist)
Definition: anisomovpt_s.c:252
int MMGS_surfballRotation(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_int *list, int ilist, double r[3][3], double *lispoi, double n[3])
Definition: anisosiz_s.c:529
int MMGS_bezierInt(MMG5_pBezier pb, double uv[2], double o[3], double no[3], double to[3])
Definition: bezier_s.c:207
int MMG5_intridmet(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int ip1, MMG5_int ip2, double s, double v[3], double mr[6])
Definition: intmet.c:163
int MMGS_moveTowardPoint(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_pPoint p, double llold, double lam0, double lam1, double lam2, double nn1[3], double nn2[3], double to[3])
Definition: movpt_s.c:555
double caleltsig_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int iel)
Definition: quality_s.c:54
int MMGS_paramDisp(MMG5_pMesh, MMG5_int, int8_t, MMG5_int, MMG5_int, double, double[3])
Definition: movpt_s.c:375
int MMG5_paratmet(double c0[3], double n0[3], double m[6], double c1[3], double n1[3], double mt[6])
Definition: mettools.c:1390
#define MG_GEO
#define MMG5_EPSOK
#define MG_MIN(a, b)
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
#define MMG5_TRIA_LMAX
static const uint8_t MMG5_inxt2[6]
#define MMG5_EPSD2
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:642
MMG5_pTria tria
Definition: libmmgtypes.h:647
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
int16_t tag[3]
Definition: libmmgtypes.h:342
MMG5_int v[3]
Definition: libmmgtypes.h:334
Structure to store surface points of a MMG mesh.
Definition: libmmgtypes.h:294
double n2[3]
Definition: libmmgtypes.h:295
double n1[3]
Definition: libmmgtypes.h:295