Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
movpt_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
36#include "libmmg3d.h"
39#include "mmgexterns_private.h"
40
59 int64_t *list,int ilist,int improve) {
60 MMG5_pTetra pt,pt0;
61 MMG5_pPoint p0,p1,p2,p3,ppt0;
62 double vol,totvol;
63 double calold,calnew,callist[MMG3D_LMAX+2];
64 double len1,len2;
65 int iloc;
66 int k,i0;
67 MMG5_int iel;
68
69 pt0 = &mesh->tetra[0];
70 ppt0 = &mesh->point[0];
71 memset(ppt0,0,sizeof(MMG5_Point));
72
73 /* Coordinates of optimal point */
74 calold = DBL_MAX;
75 totvol = 0.0;
76 for (k=0; k<ilist; k++) {
77 iel = list[k] / 4;
78 pt = &mesh->tetra[iel];
79 p0 = &mesh->point[pt->v[0]];
80 p1 = &mesh->point[pt->v[1]];
81 p2 = &mesh->point[pt->v[2]];
82 p3 = &mesh->point[pt->v[3]];
83 vol= MMG5_det4pt(p0->c,p1->c,p2->c,p3->c);
84 totvol += vol;
85 /* barycenter */
86 ppt0->c[0] += 0.25 * vol*(p0->c[0] + p1->c[0] + p2->c[0] + p3->c[0]);
87 ppt0->c[1] += 0.25 * vol*(p0->c[1] + p1->c[1] + p2->c[1] + p3->c[1]);
88 ppt0->c[2] += 0.25 * vol*(p0->c[2] + p1->c[2] + p2->c[2] + p3->c[2]);
89 calold = MG_MIN(calold, pt->qual);
90 }
91 if (totvol < MMG5_EPSD2) {
92 return 0;
93 }
94
95 totvol = 1.0 / totvol;
96 ppt0->c[0] *= totvol;
97 ppt0->c[1] *= totvol;
98 ppt0->c[2] *= totvol;
99
100 /* Check new position validity */
101 calnew = DBL_MAX;
102 i0 = -1;
103 assert ( ilist>0 );
104 for (k=0; k<ilist; k++) {
105 iel = list[k] / 4;
106 i0 = list[k] % 4;
107 pt = &mesh->tetra[iel];
108 memcpy(pt0,pt,sizeof(MMG5_Tetra));
109 pt0->v[i0] = 0;
110 callist[k] = MMG5_orcal(mesh,met,0);
111 if (callist[k] < MMG5_NULKAL) {
112 return 0;
113 }
114 calnew = MG_MIN(calnew,callist[k]);
115
116 if ( improve==2 ) {
117 for ( iloc = 0; iloc < 3; ++iloc ) {
118 len1 = MMG5_lenedg_iso(mesh,met,MMG5_arpt[i0][iloc],pt);
119 len2 = MMG5_lenedg_iso(mesh,met,MMG5_arpt[i0][iloc],pt0);
120 if ( (len1 < MMG3D_LOPTL && len2 >= MMG3D_LOPTL) ||
121 (len1 > MMG3D_LOPTL && len2 >len1 ) ) {
122 return 0;
123 }
124
125 if ( (len1 > MMG3D_LOPTS && len2 <= MMG3D_LOPTS) ||
126 (len1 < MMG3D_LOPTS && len2 <len1 ) ) {
127 return 0;
128 }
129 }
130 }
131
132 }
133 if (calold < MMG5_EPSOK && calnew <= calold) {
134 return 0;
135 }
136 else if (calnew < MMG5_EPSOK) {
137 return 0;
138 }
139 else if ( improve && calnew < 1.02 * calold ) {
140 return 0;
141 }
142 else if ( calnew < 0.3 * calold ) {
143 return 0;
144 }
145
146 /* update position */
147 assert ( i0 >=0 );
148 if ( PROctree )
149 MMG3D_movePROctree(mesh, PROctree, pt->v[i0], ppt0->c, p0->c);
150
151 p0 = &mesh->point[pt->v[i0]];
152 p0->c[0] = ppt0->c[0];
153 p0->c[1] = ppt0->c[1];
154 p0->c[2] = ppt0->c[2];
155 for (k=0; k<ilist; k++) {
156 (&mesh->tetra[list[k]/4])->qual=callist[k];
157 (&mesh->tetra[list[k]/4])->mark=mesh->mark;
158 }
159
160 return 1;
161}
162
186 MMG5_int *list,int ilist,int improve) {
187 MMG5_pTetra pt,pt0;
188 MMG5_pPoint p0,p1,p2,p3,ppt0;
189 double vol,totvol;
190 double calold,calnew,callist[MMG3D_LMAX+2];
191 double x21,y21,z21,x31,y31,z31,nx,ny,nz,bary[3],dd,len;
192 double u10[3],u20[3],u30[3],oldc[3],coe;
193 int k,ifac,iter,maxtou;
194 MMG5_int iel;
195
196 pt0 = &mesh->tetra[0];
197 ppt0 = &mesh->point[0];
198 memset(ppt0,0,sizeof(MMG5_Point));
199
200 /* Coordinates of optimal point */
201 calold = DBL_MAX;
202 totvol = 0.0;
203 assert ( ilist>0 );
204 for (k=0; k<ilist; k++) {
205 iel = list[k] / 4;
206 ifac = list[k] % 4;
207 pt = &mesh->tetra[iel];
208 assert ( MG_EOK(pt) );
209
210 p0 = &mesh->point[pt->v[ifac]];
211 memcpy(oldc,p0->c,3*sizeof(double));
212
213 p1 = &mesh->point[pt->v[MMG5_idir[ifac][0]]];
214 p2 = &mesh->point[pt->v[MMG5_idir[ifac][1]]];
215 p3 = &mesh->point[pt->v[MMG5_idir[ifac][2]]];
216
217 vol= MMG5_det4pt(p0->c,p1->c,p2->c,p3->c);
218 totvol += vol;
219
220 /* local optimal point : length 1 over the normal of the face */
221 x21 = p2->c[0]-p1->c[0];
222 y21 = p2->c[1]-p1->c[1];
223 z21 = p2->c[2]-p1->c[2];
224
225 x31 = p3->c[0]-p1->c[0];
226 y31 = p3->c[1]-p1->c[1];
227 z31 = p3->c[2]-p1->c[2];
228
229 nx = (y31*z21 - z31*y21);
230 ny = (z31*x21 - x31*z21);
231 nz = (x31*y21 - y31*x21);
232
233 dd = sqrt(nx*nx+ny*ny+nz*nz);
234 assert ( dd > 0. && "degenerated element");
235 dd = 1./dd;
236 nx *= dd;
237 ny *= dd;
238 nz *= dd;
239
240 u10[0] = p1->c[0]-p0->c[0];
241 u10[1] = p1->c[1]-p0->c[1];
242 u10[2] = p1->c[2]-p0->c[2];
243
244 u20[0] = p2->c[0]-p0->c[0];
245 u20[1] = p2->c[1]-p0->c[1];
246 u20[2] = p2->c[2]-p0->c[2];
247
248 u30[0] = p3->c[0]-p0->c[0];
249 u30[1] = p3->c[1]-p0->c[1];
250 u30[2] = p3->c[2]-p0->c[2];
251
252 assert ( met->m[pt->v[MMG5_idir[ifac][0]]] > 0. && "null metric at vertex 0" );
253 assert ( met->m[pt->v[MMG5_idir[ifac][1]]] > 0. && "null metric at vertex 1" );
254 assert ( met->m[pt->v[MMG5_idir[ifac][2]]] > 0. && "null metric at vertex 2" );
255
256 len = sqrt(u10[0]*u10[0]+u10[1]*u10[1]+u10[2]*u10[2])/met->m[pt->v[MMG5_idir[ifac][0]]]
257 + sqrt(u20[0]*u20[0]+u20[1]*u20[1]+u20[2]*u20[2])/met->m[pt->v[MMG5_idir[ifac][1]]]
258 + sqrt(u30[0]*u30[0]+u30[1]*u30[1]+u30[2]*u30[2])/met->m[pt->v[MMG5_idir[ifac][2]]];
259
260 len /= 3.;
261
262 assert ( len>0. && "degenerated element" );
263
264 len = 1./len;
265
266 /* face barycenter */
267 bary[0] = (p1->c[0]+p2->c[0]+p3->c[0])/3.;
268 bary[1] = (p1->c[1]+p2->c[1]+p3->c[1])/3.;
269 bary[2] = (p1->c[2]+p2->c[2]+p3->c[2])/3.;
270
271 /* Optimal point: barycenter of local optimal points */
272 vol = 1;
273 ppt0->c[0] += vol* ( bary[0] + nx * len );
274 ppt0->c[1] += vol* ( bary[1] + ny * len );
275 ppt0->c[2] += vol* ( bary[2] + nz * len );
276 calold = MG_MIN(calold, pt->qual);
277 }
278 if (totvol < MMG5_EPSD2) {
279 return 0;
280 }
281
282 ppt0->c[0] *= 1./(double) ilist;
283 ppt0->c[1] *= 1./(double) ilist;
284 ppt0->c[2] *= 1./(double) ilist;
285
286 coe = 0.9;
287 maxtou = 10;
288 iter = 0;
289 do {
290 p0->c[0] = (1. - coe) *oldc[0] + coe * ppt0->c[0];
291 p0->c[1] = (1. - coe) *oldc[1] + coe * ppt0->c[1];
292 p0->c[2] = (1. - coe) *oldc[2] + coe * ppt0->c[2];
293
294 /* Check new position validity */
295 calnew = DBL_MAX;
296 for (k=0; k<ilist; k++) {
297 iel = list[k] / 4;
298 pt = &mesh->tetra[iel];
299 memcpy(pt0,pt,sizeof(MMG5_Tetra));
300 callist[k] = MMG5_caltet(mesh,met,pt0); // MMG5_orcal(mesh,met,0)
301 if (calold < MMG5_EPSOK && callist[k] <= calold) {
302 break;
303 } else if ((callist[k] < MMG5_EPSOK)) {
304 break;
305 } else if( callist[k] < 0.1) {
306 if (callist[k] < 1.01*calold) break;
307 } else {
308 if (callist[k] < 1.02*calold) break;
309 }
310 calnew = MG_MIN(calnew,callist[k]);
311 }
312 if(k<ilist) {
313 coe *= 0.5;
314 continue;
315 }
316 break;
317 } while(++iter <= maxtou );
318
319 if ( iter > maxtou ) {
320 memcpy(p0->c,oldc,3*sizeof(double));
321 return 0;
322 }
323
324 /* update position */
325 if ( PROctree )
326 MMG3D_movePROctree(mesh, PROctree, mesh->tetra[list[0]/4].v[list[0]%4], ppt0->c, p0->c);
327
328 for (k=0; k<ilist; k++) {
329 (&mesh->tetra[list[k]/4])->qual=callist[k];
330 (&mesh->tetra[list[k]/4])->mark=mesh->mark;
331 }
332
333 return 1;
334}
335
350int MMG3D_rotate_surfacicBall(MMG5_pMesh mesh,MMG5_int *lists,int ilists,MMG5_int ip0,
351 double r[3][3],double *lispoi) {
352 MMG5_pTetra pt;
353 MMG5_pPoint p0,p1;
354 double ux,uy,uz,det2d;
355 MMG5_int k,na,nb,ntempa,ntempb;
356 int l;
357 uint8_t iface,i;
358
359 k = lists[0] / 4;
360 iface = lists[0] % 4;
361 pt = &mesh->tetra[k];
362 p0 = &mesh->point[ip0];
363
364 na = nb = 0;
365 for (i=0; i<3; i++) {
366 if ( pt->v[MMG5_idir[iface][i]] != ip0 ) {
367 if ( !na )
368 na = pt->v[MMG5_idir[iface][i]];
369 else
370 nb = pt->v[MMG5_idir[iface][i]];
371 }
372 }
373
374 for (l=1; l<ilists; l++) {
375 k = lists[l] / 4;
376 iface = lists[l] % 4;
377 pt = &mesh->tetra[k];
378 ntempa = ntempb = 0;
379 for (i=0; i<3; i++) {
380 if ( pt->v[MMG5_idir[iface][i]] != ip0 ) {
381 if ( !ntempa )
382 ntempa = pt->v[MMG5_idir[iface][i]];
383 else
384 ntempb = pt->v[MMG5_idir[iface][i]];
385 }
386 }
387 if ( ntempa == na )
388 p1 = &mesh->point[na];
389 else if ( ntempa == nb )
390 p1 = &mesh->point[nb];
391 else if ( ntempb == na )
392 p1 = &mesh->point[na];
393 else {
394 assert(ntempb == nb);
395 p1 = &mesh->point[nb];
396 }
397 ux = p1->c[0] - p0->c[0];
398 uy = p1->c[1] - p0->c[1];
399 uz = p1->c[2] - p0->c[2];
400
401 lispoi[3*l+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
402 lispoi[3*l+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
403 lispoi[3*l+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
404
405 na = ntempa;
406 nb = ntempb;
407 }
408
409 /* Finish with point 0 */;
410 k = lists[0] / 4;
411 iface = lists[0] % 4;
412 pt = &mesh->tetra[k];
413 ntempa = ntempb = 0;
414 for (i=0; i<3; i++) {
415 if ( pt->v[MMG5_idir[iface][i]] != ip0 ) {
416 if ( !ntempa )
417 ntempa = pt->v[MMG5_idir[iface][i]];
418 else
419 ntempb = pt->v[MMG5_idir[iface][i]];
420 }
421 }
422 if ( ntempa == na )
423 p1 = &mesh->point[na];
424 else if ( ntempa == nb )
425 p1 = &mesh->point[nb];
426 else if ( ntempb == na )
427 p1 = &mesh->point[na];
428 else {
429 assert(ntempb == nb);
430 p1 = &mesh->point[nb];
431 }
432
433 ux = p1->c[0] - p0->c[0];
434 uy = p1->c[1] - p0->c[1];
435 uz = p1->c[2] - p0->c[2];
436
437 lispoi[1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
438 lispoi[2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
439 lispoi[3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
440
441 /* list goes modulo ilist */
442 lispoi[3*ilists+1] = lispoi[1];
443 lispoi[3*ilists+2] = lispoi[2];
444 lispoi[3*ilists+3] = lispoi[3];
445
449 /* Check all projections over tangent plane. */
450 for (k=0; k<ilists-1; k++) {
451 det2d = lispoi[3*k+1]*lispoi[3*(k+1)+2] - lispoi[3*k+2]*lispoi[3*(k+1)+1];
452 if ( det2d < 0.0 ) {
453 return 0;
454 }
455 }
456 det2d = lispoi[3*(ilists-1)+1]*lispoi[3*0+2] - lispoi[3*(ilists-1)+2]*lispoi[3*0+1];
457 if ( det2d < 0.0 ) {
458 return 0;
459 }
460
461 return 1;
462}
463
464
483int MMG3D_movbdyregpt_geom(MMG5_pMesh mesh,MMG5_int *lists,const MMG5_int kel,
484 const MMG5_int ip0,double n[3],double lambda[3],double o[3],
485 double no[3]) {
486 MMG5_pTetra pt;
487 MMG5_pxTetra pxt;
488 MMG5_pPoint p1,p2,ppt0,p0;
489 MMG5_Tria tt;
490 MMG5_pxPoint pxp;
491 MMG5_Bezier b;
492 double uv[2],to[3],detloc;
493 int iel,na,nb,ntempb,ntempc,nxp;
494 uint8_t iface,i;
495 static int8_t mmgErr0=0,mmgErr1=0;
496
497 iel = lists[kel] / 4;
498 iface = lists[kel] % 4;
499 pt = &mesh->tetra[iel];
500 pxt = &mesh->xtetra[pt->xt];
501 p0 = &mesh->point[ip0];
502
503 assert( 0<=iface && iface<4 && "unexpected local face idx");
504 MMG5_tet2tri(mesh,iel,iface,&tt);
505
506 if(!MMG5_bezierCP(mesh,&tt,&b,MG_GET(pxt->ori,iface))){
507 if( !mmgErr0 ) {
508 mmgErr0 = 1;
509 fprintf(stderr,"\n ## Error: %s: function MMG5_bezierCP return 0.\n",
510 __func__);
511 }
512 return -1;
513 }
514
515 /* Now, for Bezier interpolation, one should identify which of i,i1,i2 is
516 0,1,2 recall uv[0] = barycentric coord associated to pt->v[1], uv[1]
517 associated to pt->v[2] and 1-uv[0]-uv[1] is associated to pt->v[0]. For
518 this, use the fact that kel, kel + 1 is positively oriented with respect to
519 n */
520 na = nb = 0;
521 for( i=0 ; i<4 ; i++ ){
522 if ( (pt->v[i] != ip0) && (pt->v[i] != pt->v[iface]) ) {
523 if ( !na )
524 na = pt->v[i];
525 else
526 nb = pt->v[i];
527 }
528 }
529 p1 = &mesh->point[na];
530 p2 = &mesh->point[nb];
531 detloc = MMG5_det3pt1vec(p0->c,p1->c,p2->c,n);
532
533 /* ntempa=point to which is associated 1-uv[0]-uv[1], ntempb=uv[0], ntempc=uv[1] */
534 ntempb = pt->v[MMG5_idir[iface][1]];
535 ntempc = pt->v[MMG5_idir[iface][2]];
536
537 /* na = lispoi[kel] -> lambda[1], nb = lispoi[kel+1] -> lambda[2] */
538 if ( detloc > 0.0 ) {
539 if ( ntempb == na )
540 uv[0] = lambda[1];
541 else if (ntempb == nb )
542 uv[0] = lambda[2];
543 else {
544 assert(ntempb == ip0);
545 uv[0] = lambda[0];
546 }
547 if ( ntempc == na )
548 uv[1] = lambda[1];
549 else if (ntempc == nb )
550 uv[1] = lambda[2];
551 else {
552 assert(ntempc == ip0);
553 uv[1] = lambda[0];
554 }
555 }
556 /* nb = lispoi[kel] -> lambda[1], na = lispoi[kel+1] -> lambda[2] */
557 else {
558 if ( ntempb == na )
559 uv[0] = lambda[2];
560 else if (ntempb == nb )
561 uv[0] = lambda[1];
562 else {
563 assert(ntempb == ip0);
564 uv[0] = lambda[0];
565 }
566 if ( ntempc == na )
567 uv[1] = lambda[2];
568 else if (ntempc == nb )
569 uv[1] = lambda[1];
570 else {
571 assert(ntempc == ip0);
572 uv[1] = lambda[0];
573 }
574 }
575 if(!MMG3D_bezierInt(&b,uv,o,no,to)){
576 if( !mmgErr1 ) {
577 mmgErr1 = 1;
578 fprintf(stderr," ## Error: %s: function MMG3D_bezierInt return 0.\n",
579 __func__);
580 }
581 return -1;
582 }
583
584 /* Test : make sure that geometric approximation has not been degraded too much */
585 ppt0 = &mesh->point[0];
586 ppt0->c[0] = o[0];
587 ppt0->c[1] = o[1];
588 ppt0->c[2] = o[2];
589
590 ppt0->tag = p0->tag;
591 ppt0->ref = p0->ref;
592
593
594 nxp = mesh->xp + 1;
595 if ( nxp > mesh->xpmax ) {
597 "larger xpoint table",
598 return 0);
599 }
600 ppt0->xp = nxp;
601 pxp = &mesh->xpoint[nxp];
602 memcpy(pxp,&(mesh->xpoint[p0->xp]),sizeof(MMG5_xPoint));
603 pxp->n1[0] = no[0];
604 pxp->n1[1] = no[1];
605 pxp->n1[2] = no[2];
606
607 return nxp;
608}
609
627 int ilistv,MMG5_int *lists,int ilists,
628 int improveSurf,int improveVol) {
629 MMG5_pTetra pt,pt0;
630 MMG5_pPoint p0;
631 MMG5_Tria tt;
632 MMG5_pxPoint pxp;
633 double n[3],r[3][3],lispoi[3*MMG3D_LMAX+1],ux,uy,det2d;
634 double detloc,oppt[2],step,lambda[3];
635 double ll,m[2],o[3],no[3];
636 double calold,calnew,caltmp,callist[MMG3D_LMAX+2];
637 int l,nut,nxp;
638 MMG5_int kel,k,ip0;
639 uint8_t i0,iface,i;
640
641 step = 0.1;
642 nut = 0;
643 oppt[0] = 0.0;
644 oppt[1] = 0.0;
645 if ( ilists < 2 ) return 0;
646
647 k = listv[0] / 4;
648 i0 = listv[0] % 4;
649 pt = &mesh->tetra[k];
650 ip0 = pt->v[i0];
651 p0 = &mesh->point[ip0];
652 assert( p0->xp && !MG_EDG(p0->tag) );
653
654 /* Don't use a pointer for n to avoid issues with the reallocation of the
655 * xpoint array and invalid pointers (see ls-CenIn-DisOut-8 test of ParMmg) */
656 n[0] = mesh->xpoint[p0->xp].n1[0];
657 n[1] = mesh->xpoint[p0->xp].n1[1];
658 n[2] = mesh->xpoint[p0->xp].n1[2];
659
661 if ( !MMG5_rotmatrix(n,r) ) return 0;
662
665 if ( !MMG3D_rotate_surfacicBall(mesh,lists,ilists,ip0,r,lispoi) ) {
666 return 0;
667 }
668
671 for (k=0; k<ilists; k++) {
672 m[0] = 0.5*(lispoi[3*(k+1)+1] + lispoi[3*k+1]);
673 m[1] = 0.5*(lispoi[3*(k+1)+2] + lispoi[3*k+2]);
674 ux = lispoi[3*(k+1)+1] - lispoi[3*k+1];
675 uy = lispoi[3*(k+1)+2] - lispoi[3*k+2];
676 ll = ux*ux + uy*uy;
677 if ( ll < MMG5_EPSD2 ) continue;
678 nut++;
679 oppt[0] += (m[0]-MMG5_SQR32*uy);
680 oppt[1] += (m[1]+MMG5_SQR32*ux);
681 }
682 oppt[0] *= (1.0 / nut);
683 oppt[1] *= (1.0 / nut);
684
686 det2d = lispoi[1]*oppt[1] - lispoi[2]*oppt[0];
687 kel = 0;
688 if ( det2d >= 0.0 ) {
689 for (k=0; k<ilists; k++) {
690 detloc = oppt[0]*lispoi[3*(k+1)+2] - oppt[1]*lispoi[3*(k+1)+1];
691 if ( detloc >= 0.0 ) {
692 kel = k;
693 break;
694 }
695 }
696 if ( k == ilists ) return 0;
697 }
698 else {
699 for (k=ilists-1; k>=0; k--) {
700 detloc = lispoi[3*k+1]*oppt[1] - lispoi[3*k+2]*oppt[0];
701 if ( detloc >= 0.0 ) {
702 kel = k;
703 break;
704 }
705 }
706 if ( k == -1 ) return 0;
707 }
708
709 /* Sizing of time step : make sure point does not go out corresponding triangle. */
710 det2d = -oppt[1]*(lispoi[3*(kel+1)+1] - lispoi[3*(kel)+1]) + \
711 oppt[0]*(lispoi[3*(kel+1)+2] - lispoi[3*(kel)+2]);
712 if ( fabs(det2d) < MMG5_EPSD2 ) return 0;
713
714 det2d = 1.0 / det2d;
715 step *= det2d;
716
717 det2d = lispoi[3*(kel)+1]*(lispoi[3*(kel+1)+2] - lispoi[3*(kel)+2]) - \
718 lispoi[3*(kel)+2 ]*(lispoi[3*(kel+1)+1] - lispoi[3*(kel)+1]);
719 step *= det2d;
720 step = fabs(step);
721 oppt[0] *= step;
722 oppt[1] *= step;
723
724 /* Computation of the barycentric coordinates of the new point in the corresponding triangle. */
725 det2d = lispoi[3*kel+1]*lispoi[3*(kel+1)+2] - lispoi[3*kel+2]*lispoi[3*(kel+1)+1];
726 if ( det2d < MMG5_EPSD2 ) return 0;
727 det2d = 1.0 / det2d;
728 lambda[1] = lispoi[3*(kel+1)+2]*oppt[0] - lispoi[3*(kel+1)+1]*oppt[1];
729 lambda[2] = -lispoi[3*(kel)+2]*oppt[0] + lispoi[3*(kel)+1]*oppt[1];
730 lambda[1]*= (det2d);
731 lambda[2]*= (det2d);
732 lambda[0] = 1.0 - lambda[1] - lambda[2];
733
735 // Remark: if we call following function with a pointer for n, we have to set
736 // the pointer again after the function call as it may invalidate it if it
737 // reallocates the xpoint array
738 nxp = MMG3D_movbdyregpt_geom(mesh,lists,kel,ip0,n,lambda,o,no);
739 if ( nxp < 0 ) {
740 return -1;
741 }
742 else if ( !nxp ) {
743 return 0;
744 }
745 pxp = &mesh->xpoint[nxp];
746
747 /* For each surfacic triangle, build a virtual displaced triangle for check purposes */
748 calold = calnew = DBL_MAX;
749 for (l=0; l<ilists; l++) {
750 k = lists[l] / 4;
751 iface = lists[l] % 4;
752
753 assert( 0<=iface && iface<4 && "unexpected local face idx");
754 MMG5_tet2tri(mesh,k,iface,&tt);
755 calold = MG_MIN(calold,MMG5_caltri(mesh,met,&tt));
756
757 for( i=0 ; i<3 ; i++ )
758 if ( tt.v[i] == ip0 ) break;
759 assert(i<3);
760 if ( i==3 ) return 0;
761
762 tt.v[i] = 0;
763
764 caltmp = MMG5_caltri(mesh,met,&tt);
765 if ( caltmp < MMG5_EPSD2 ) {
766 /* We don't check the input triangle qualities, thus we may have a very
767 * bad triangle in our mesh */
768 return 0;
769 }
770 calnew = MG_MIN(calnew,caltmp);
771 }
772 if ( calold < MMG5_EPSOK && calnew <= calold ) return 0;
773 else if (calnew < MMG5_EPSOK) return 0;
774 else if (improveSurf && calnew < 1.02*calold) return 0;
775 else if ( calnew < 0.3*calold ) return 0;
776 memset(pxp,0,sizeof(MMG5_xPoint));
777
778 /* Test : check whether all volumes remain positive with new position of the point */
779 calold = calnew = DBL_MAX;
780
781 for (l=0; l<ilistv; l++) {
782 k = listv[l] / 4;
783 i0 = listv[l] % 4;
784 pt = &mesh->tetra[k];
785 pt0 = &mesh->tetra[0];
786 memcpy(pt0,pt,sizeof(MMG5_Tetra));
787 pt0->v[i0] = 0;
788 calold = MG_MIN(calold, pt->qual);
789 callist[l]=MMG5_orcal(mesh,met,0);
790
791 if (callist[l] < MMG5_NULKAL) {
792 return 0;
793 }
794 calnew = MG_MIN(calnew,callist[l]);
795
796 }
797
798
799 if (calold < MMG5_EPSOK && calnew <= calold) {
800 return 0;
801 }
802 else if (calnew < MMG5_EPSOK) {
803 return 0;
804 }
805 else if (improveVol && calnew < calold) {
806 return 0;
807 }
808 else if (calnew < 0.3*calold) {
809 return 0;
810 }
811
812 /* When all tests have been carried out, update coordinates and normals */
813 if ( PROctree )
814 MMG3D_movePROctree(mesh, PROctree, ip0, o, p0->c);
815
816 p0->c[0] = o[0];
817 p0->c[1] = o[1];
818 p0->c[2] = o[2];
819
820 n[0] = no[0];
821 n[1] = no[1];
822 n[2] = no[2];
823
824 for(l=0; l<ilistv; l++){
825 (&mesh->tetra[listv[l]/4])->qual= callist[l];
826 (&mesh->tetra[listv[l]/4])->mark=mesh->mark;
827 }
828 return 1;
829}
830
852static inline
853int MMG3D_curveEndingPts_chkEdg(MMG5_pMesh mesh,MMG5_int *lists,int l,MMG5_int ip0,
854 MMG5_int *ipa,MMG5_int *ipb,const uint16_t edgTag,MMG5_int *ip) {
855
856 MMG5_pTetra pt;
857 MMG5_int iel,iptmpa,iptmpb;
858 uint16_t tag;
859 uint8_t i,ie,iface,iea,ieb;
860
861 iel = lists[l] / 4;
862 iface = lists[l] % 4;
863 pt = &mesh->tetra[iel];
864 iea = ieb = 0;
865
866 assert ( pt->xt && "tetra with boundary face has a xtetra");
867
868 /* For each bdy face that contains ip0, store the index of the 2 edges
869 * passing through \a ip0 in \a iea and \a ieb. */
870 for (i=0; i<3; i++) {
871 ie = MMG5_iarf[iface][i]; //index in tet of edge i on face iface
872 if ( (pt->v[MMG5_iare[ie][0]] == ip0) || (pt->v[MMG5_iare[ie][1]] == ip0) ) {
873 if ( !iea )
874 iea = ie;
875 else
876 ieb = ie;
877 }
878 }
879 /* In current face (\a iface), store in \a iptmpa the global index of the
880 * second vertex of edge \a iea (first vertex being \a ip0). */
881 if ( pt->v[MMG5_iare[iea][0]] != ip0 )
882 iptmpa = pt->v[MMG5_iare[iea][0]];
883 else {
884 assert(pt->v[MMG5_iare[iea][1]] != ip0);
885 iptmpa = pt->v[MMG5_iare[iea][1]];
886 }
887 /* In current face (\a iface), store in \a iptmpb the global index of the
888 * second vertex of edge \a ieb (first vertex being \a ip0). */
889 if ( pt->v[MMG5_iare[ieb][0]] != ip0 )
890 iptmpb = pt->v[MMG5_iare[ieb][0]];
891 else {
892 assert(pt->v[MMG5_iare[ieb][1]] != ip0);
893 iptmpb = pt->v[MMG5_iare[ieb][1]];
894 }
895
896 /* Search if the edge ip0-iptmpa is the edge at the interface with previous
897 * triangle. */
898 if ( (iptmpa == *ipa) || (iptmpa == *ipb) ) {
899 tag = mesh->xtetra[pt->xt].tag[iea];
900 if ( edgTag & tag ) {
901 /* The featured edge has been found. End of ball processing. */
902 *ip = iptmpa;
903 return 1;
904 }
905 }
906
907 /* Search if the edge ip0-iptmpb is the edge at the interface with previous
908 * triangle. */
909 if ( (iptmpb == *ipa) || (iptmpb == *ipb) ) {
910 tag = mesh->xtetra[pt->xt].tag[ieb];
911 if ( edgTag & tag ) {
912 /* The featured edge has been found. End of ball processing. */
913 *ip = iptmpb;
914 return 1;
915 }
916 }
917
918 /* Update face vertices for next item processing */
919 *ipa = iptmpa;
920 *ipb = iptmpb;
921
922 return 0;
923}
924
944int MMG3D_curveEndingPts(MMG5_pMesh mesh,MMG5_int *lists,int ilists,
945 const uint16_t edgTag, MMG5_int ip0,MMG5_int *ip1,
946 MMG5_int *ip2) {
947 MMG5_pTetra pt;
948 MMG5_int iel,ipa,ipb;
949 int l;
950 uint8_t i,iface;
951
957 /* Get first edge to initialize the loop: \a ip0 is the global idx of the
958 * point we want to move, store in \a ipa and \a ipb the global indices of the
959 * 2 other vertices of the boundary face from which we start. When processing
960 * next triangle we will find either the edge ip0-ipa, or ip0-ipb, this will
961 * be the first edge that we will check. */
962 iel = lists[0]/4;
963 iface = lists[0]%4;
964 pt = &mesh->tetra[iel];
965 ipa = ipb = 0;
966 for (i=0; i<3; i++) {
967 if ( pt->v[MMG5_idir[iface][i]] != ip0 ) {
968 if ( !ipa )
969 ipa = pt->v[MMG5_idir[iface][i]];
970 else
971 ipb = pt->v[MMG5_idir[iface][i]];
972 }
973 }
974 assert(ipa && ipb);
975
976 /* Travel surfacic list of \a ip0 and search if the edge at interface of
977 * boundary triangles stored in lists[l] and lists[l-1] belongs to our curve
978 * (\a edgTag edge). */
979 for (l=1; l<ilists; l++) {
980 if ( MMG3D_curveEndingPts_chkEdg(mesh,lists,l,ip0,&ipa,&ipb,edgTag,ip1) ) {
981 break;
982 }
983 }
984
991 /* Get first edge to initialize the loop: \a ip0 is the global idx of the
992 * point we want to move, store in \a ipa and \a ipb the global indices of the
993 * 2 other vertices of the boundary face from which we start. When processing
994 * next triangle we will find either the edge ip0-ipa, or ip0-ipb, this will
995 * be the first edge that we will check. */
996 iel = lists[0]/4;
997 iface = lists[0]%4;
998 pt = &mesh->tetra[iel];
999 ipa = ipb = 0;
1000 for (i=0; i<3; i++) {
1001 if ( pt->v[MMG5_idir[iface][i]] != ip0 ) {
1002 if ( !ipa )
1003 ipa = pt->v[MMG5_idir[iface][i]];
1004 else
1005 ipb = pt->v[MMG5_idir[iface][i]];
1006 }
1007 }
1008 assert(ipa && ipb);
1009
1010 /* Travel surfacic list of \a ip0 and search if the edge at interface of
1011 * boundary triangles stored in lists[l] and lists[l+1] belongs to our curve
1012 * (\a edgTag edge). */
1013 for (l=ilists-1; l>0; l--) {
1014 if ( MMG3D_curveEndingPts_chkEdg(mesh,lists,l,ip0,&ipa,&ipb,edgTag,ip2) ) {
1015 break;
1016 }
1017 }
1018
1019 /* Check that we have found two distinct ending points */
1020 if ( !(*ip1) ) {
1021 return 0;
1022 }
1023 if ( !(*ip2) ) {
1024 return 0;
1025 }
1026 if ( (*ip1) == (*ip2) ) {
1027 return 0;
1028 }
1029
1030 return 1;
1031}
1032
1057 MMG3D_pPROctree PROctree, int64_t *listv,
1058 int ilistv,int improve,MMG5_pPoint p0,
1059 MMG5_int ip0,uint8_t isrid,double o[3],
1060 double no[3],double no2[3],double to[3]) {
1061
1062 MMG5_pTetra pt,pt0;
1063 MMG5_pxPoint pxp;
1064 double calold,calnew,callist[MMG3D_LMAX+2];
1065 MMG5_int iel;
1066 int l;
1067 int8_t i0;
1068
1070 calold = calnew = DBL_MAX;
1071
1072 for( l=0 ; l<ilistv ; l++ ){
1073 iel = listv[l] / 4;
1074 i0 = listv[l] % 4;
1075 pt = &mesh->tetra[iel];
1076 pt0 = &mesh->tetra[0];
1077 memcpy(pt0,pt,sizeof(MMG5_Tetra));
1078 pt0->v[i0] = 0;
1079 calold = MG_MIN(calold, pt->qual);
1080 callist[l] = MMG5_orcal(mesh,met,0);
1081 if (callist[l] < MMG5_NULKAL) {
1082 return 0;
1083 }
1084 calnew = MG_MIN(calnew,callist[l]);
1085 }
1086 if ((calold < MMG5_EPSOK && calnew <= calold) ||
1087 (calnew < MMG5_EPSOK) || (calnew <= 0.3*calold)) {
1088 return 0;
1089 } else if (improve && calnew < calold) {
1090 return 0;
1091 }
1092
1094 if ( PROctree ) {
1095 MMG3D_movePROctree(mesh, PROctree, ip0, o, p0->c);
1096 }
1097
1098 p0->c[0] = o[0];
1099 p0->c[1] = o[1];
1100 p0->c[2] = o[2];
1101
1102 pxp = &mesh->xpoint[p0->xp];
1103 pxp->n1[0] = no[0];
1104 pxp->n1[1] = no[1];
1105 pxp->n1[2] = no[2];
1106
1107 p0->n[0] = to[0];
1108 p0->n[1] = to[1];
1109 p0->n[2] = to[2];
1110
1111 if ( isrid ) {
1112 /* Copy the second normal for ridge point */
1113 pxp->n2[0] = no2[0];
1114 pxp->n2[1] = no2[1];
1115 pxp->n2[2] = no2[2];
1116 }
1117
1118 for( l=0 ; l<ilistv ; l++ ){
1119 (&mesh->tetra[listv[l]/4])->qual = callist[l];
1120 (&mesh->tetra[listv[l]/4])->mark = mesh->mark;
1121 }
1122 return 1;
1123}
1124
1151 MMG5_int ip1,MMG5_int ip2,double ll1old,double ll2old,
1152 uint8_t isrid,const double step,
1153 double o[3],double no[3],
1154 double no2[3],double to[3],
1155 const uint16_t edgTag) {
1156
1157 MMG5_int ip;
1158
1160 if ( ll1old < ll2old ) {
1161 /* move towards p2 */
1162 ip = ip2;
1163 }
1164 else if ( ll1old > ll2old ) {
1165 /* move towards p1 */
1166 ip = ip1;
1167 }
1168 else {
1169 return 0;
1170 }
1171
1173 if ( MG_NOM & edgTag ) {
1174 if ( !(MMG5_BezierNom(mesh,ip0,ip,step,o,no,to)) ) {
1175 return 0;
1176 }
1177 }
1178 else if ( MG_GEO & edgTag ) {
1179 // Remark: Singular points are required so following assertion should be
1180 // verified in the entire function. Keep the test here to make easier
1181 // debugging/understanding when passing here.
1182 assert ( (!MG_SIN(mesh->point[ip0].tag)) &&
1183 "BezierRidge don't work if both ip0 and ip are singular" );
1184 if ( !(MMG5_BezierRidge(mesh,ip0,ip,step,o,no,no2,to)) ) {
1185 return 0;
1186 }
1187 }
1188 else if ( MG_REF & edgTag ) {
1189 if ( !(MMG5_BezierRef(mesh,ip0,ip,step,o,no,to)) ) {
1190 return 0;
1191 }
1192 }
1193 else {
1194 assert ( 0 && "Unexpected edge tag in this function");
1195 return 0;
1196 }
1197
1199 MMG5_pPoint ppt0 = &mesh->point[0];
1200 ppt0->c[0] = o[0];
1201 ppt0->c[1] = o[1];
1202 ppt0->c[2] = o[2];
1203 ppt0->tag = p0->tag;
1204 ppt0->ref = p0->ref;
1205
1206
1207 MMG5_int nxp = mesh->xp + 1;
1208 if ( nxp > mesh->xpmax ) {
1210 "larger xpoint table",
1211 return 0);
1212 }
1213 ppt0->xp = nxp;
1214 MMG5_pxPoint pxp = &mesh->xpoint[nxp];
1215 memcpy(pxp,&(mesh->xpoint[p0->xp]),sizeof(MMG5_xPoint));
1216
1217 ppt0->n[0] = to[0];
1218 ppt0->n[1] = to[1];
1219 ppt0->n[2] = to[2];
1220
1221 pxp->n1[0] = no[0];
1222 pxp->n1[1] = no[1];
1223 pxp->n1[2] = no[2];
1224
1225 if ( isrid ) {
1226 /* Copy the second normal for ridge point */
1227 pxp->n2[0] = no2[0];
1228 pxp->n2[1] = no2[1];
1229 pxp->n2[2] = no2[2];
1230 }
1231
1232 return ip;
1233}
1234
1235
1262static inline
1264 int ilistv, MMG5_int *lists, int ilists,int improve,const int16_t edgTag){
1265 MMG5_pTetra pt;
1266 MMG5_pxTetra pxt;
1267 MMG5_pPoint p0,p1,p2;
1268 MMG5_Tria tt;
1269 MMG5_pPar par;
1270 double ll1old,ll2old,o[3],no[3],no2[3],to[3];
1271 double calold,calnew,caltmp,hmax,hausd;
1272 MMG5_int iel,ip0,ip1,ip2,ip;
1273 int l;
1274 int isloc,j;
1275 uint8_t i,iface,isrid;
1276
1277 ip1 = ip2 = 0;
1278 pt = &mesh->tetra[listv[0]/4];
1279 ip0 = pt->v[listv[0]%4];
1280 p0 = &mesh->point[ip0];
1281
1284 isrid = ((MG_GEO & edgTag) && !(MG_NOM & edgTag));
1285
1286 assert ( edgTag & p0->tag );
1287
1290 int ier = MMG3D_curveEndingPts(mesh,lists,ilists,edgTag,ip0,&ip1,&ip2);
1291 if ( !ier ) {
1292 return 0;
1293 }
1294
1301 p1 = &mesh->point[ip1];
1302 p2 = &mesh->point[ip2];
1303
1304 ll1old = (p1->c[0] -p0->c[0])* (p1->c[0] -p0->c[0]) \
1305 + (p1->c[1] -p0->c[1])* (p1->c[1] -p0->c[1]) \
1306 + (p1->c[2] -p0->c[2])* (p1->c[2] -p0->c[2]);
1307 ll2old = (p2->c[0] -p0->c[0])* (p2->c[0] -p0->c[0]) \
1308 + (p2->c[1] -p0->c[1])* (p2->c[1] -p0->c[1]) \
1309 + (p2->c[2] -p0->c[2])* (p2->c[2] -p0->c[2]);
1310
1313 ip = MMG3D_movbdycurvept_newPosForSimu( mesh,p0,ip0,ip1,ip2,ll1old,ll2old,
1314 isrid,MMG3D_MOVSTEP,o,no,no2,to,edgTag );
1315 if ( !ip ) {
1316 return 0;
1317 }
1318
1328 calold = calnew = DBL_MAX;
1329 for( l=0 ; l<ilists ; l++ ){
1330 iel = lists[l] / 4;
1331 iface = lists[l] % 4;
1332
1333 assert( 0<=iface && iface<4 && "unexpected local face idx");
1334 MMG5_tet2tri(mesh,iel,iface,&tt);
1335 caltmp = MMG5_caltri(mesh,met,&tt);
1336 calold = MG_MIN(calold,caltmp);
1337
1338 for( i=0 ; i<3 ; i++ ) {
1339 if ( tt.v[i] == ip0 ) {
1340 break;
1341 }
1342 }
1343 assert(i<3);
1344 if ( i==3 ) {
1345 return 0;
1346 }
1347
1348 tt.v[i] = 0;
1349
1350 caltmp = MMG5_caltri(mesh,met,&tt);
1351 if ( caltmp < MMG5_EPSD2 ) {
1352 /* We don't check the input triangle qualities, thus we may have a very
1353 * bad triangle in our mesh */
1354 return 0;
1355 }
1356 calnew = MG_MIN(calnew,caltmp);
1357
1358 /* Local parameters for tt and iel */
1359 pt = &mesh->tetra[iel];
1360 pxt = &mesh->xtetra[pt->xt];
1361
1362 hmax = mesh->info.hmax;
1363 hausd = mesh->info.hausd;
1364
1365 isloc = 0;
1366 if ( mesh->info.parTyp & MG_Tetra ) {
1367 for ( j=0; j<mesh->info.npar; ++j ) {
1368 par = &mesh->info.par[j];
1369
1370 if ( par->elt != MMG5_Tetrahedron ) continue;
1371 if ( par->ref != pt->ref ) continue;
1372
1373 hmax = par->hmax;
1374 hausd = par->hausd;
1375 isloc = 1;
1376 break;
1377 }
1378 }
1379 if ( mesh->info.parTyp & MG_Tria ) {
1380 if ( isloc ) {
1381 for ( j=0; j<mesh->info.npar; ++j ) {
1382 par = &mesh->info.par[j];
1383
1384 if ( par->elt != MMG5_Triangle ) continue;
1385 if ( par->ref != tt.ref ) continue;
1386
1387 hmax = MG_MIN(hmax,par->hmax);
1388 hausd = MG_MIN(hausd,par->hausd);
1389 break;
1390 }
1391 }
1392 else {
1393 for ( j=0; j<mesh->info.npar; ++j ) {
1394 par = &mesh->info.par[j];
1395
1396 if ( par->elt != MMG5_Triangle ) continue;
1397 if ( par->ref != tt.ref ) continue;
1398
1399 hmax = par->hmax;
1400 hausd = par->hausd;
1401 isloc = 1;
1402 break;
1403 }
1404 }
1405 }
1406
1407 if ( MMG5_chkedg(mesh,&tt,MG_GET(pxt->ori,iface),hmax,hausd,isloc) > 0 ) {
1408 memset(&mesh->xpoint[mesh->point[0].xp],0,sizeof(MMG5_xPoint));
1409 return 0;
1410 }
1411 }
1412 if ( calold < MMG5_EPSOK && calnew <= calold ) {
1413 return 0;
1414 }
1415 else if ( calnew < calold ) {
1416 return 0;
1417 }
1418 memset(&mesh->xpoint[mesh->point[0].xp],0,sizeof(MMG5_xPoint));
1419
1423 ier = MMG3D_movbdycurvept_chckAndUpdate(mesh,met,PROctree,listv,ilistv,
1424 improve,p0,ip0,isrid,o,no,no2,to);
1425
1426 return ier;
1427}
1428
1447 int ilistv, MMG5_int *lists, int ilists,int improve){
1448
1449 return MMG3D_movbdycurvept_iso(mesh,met,PROctree,listv,ilistv,lists,ilists,improve,MG_REF);
1450}
1451
1471 int ilistv, MMG5_int *lists, int ilists,int improve){
1472
1473 return MMG3D_movbdycurvept_iso(mesh,met,PROctree,listv,ilistv,lists,ilists,improve,MG_NOM);
1474}
1475
1491 int ilistv, int improve){
1492 MMG5_pTetra pt,pt0;
1493 MMG5_pxTetra pxt;
1494 MMG5_pPoint p0,p1,p2,ppt0;
1495 double step,ll1old,ll2old,calold,calnew,callist[MMG3D_LMAX+2];
1496 double o[3],no[3],to[3];
1497 int l;
1498 MMG5_int ip0,ip1,ip2,ip,iel,ipa;
1499 int8_t i,i0,ie;
1500
1501 step = 0.1;
1502 ip1 = ip2 = 0;
1503 pt = &mesh->tetra[listv[0]/4];
1504 ip0 = pt->v[listv[0]%4];
1505 p0 = &mesh->point[ip0];
1506
1507 assert ( (p0->tag & MG_NOM) && p0->xp && mesh->xpoint[p0->xp].nnor );
1508
1509 /* Recover the two ending points of the underlying non manifold curve */
1510 for (l=0; l<ilistv; l++) {
1511 iel = listv[l] / 4;
1512 i0 = listv[l] % 4;
1513 pt = &mesh->tetra[iel];
1514 if ( !pt->xt ) continue;
1515 pxt = &mesh->xtetra[pt->xt];
1516
1517 for (i=0; i<3; i++) {
1518 ie = MMG5_arpt[i0][i];
1519 if ( pxt->tag[ie] & MG_NOM ) {
1520 ipa = ( ip0 == pt->v[MMG5_iare[ie][0]] ) ? pt->v[MMG5_iare[ie][1]] : pt->v[MMG5_iare[ie][0]];
1521 if ( !ip1 ) ip1 = ipa;
1522 else if ( !ip2 && ipa != ip1 ) ip2 = ipa;
1523 }
1524 }
1525 }
1526 if ( !(ip1 && ip2 && (ip1 != ip2)) ) return 0;
1527
1528 /* At this point, we get the point extremities ip1, ip2 of the non manifold curve passing through ip0 */
1529 p1 = &mesh->point[ip1];
1530 p2 = &mesh->point[ip2];
1531
1532 ll1old = (p1->c[0] -p0->c[0])* (p1->c[0] -p0->c[0]) \
1533 + (p1->c[1] -p0->c[1])* (p1->c[1] -p0->c[1]) \
1534 + (p1->c[2] -p0->c[2])* (p1->c[2] -p0->c[2]);
1535 ll2old = (p2->c[0] -p0->c[0])* (p2->c[0] -p0->c[0]) \
1536 + (p2->c[1] -p0->c[1])* (p2->c[1] -p0->c[1]) \
1537 + (p2->c[2] -p0->c[2])* (p2->c[2] -p0->c[2]);
1538
1539 if ( ll1old < ll2old ) { //move towards p2
1540 ip = ip2;
1541 }
1542 else {
1543 ip = ip1;
1544 }
1545
1546 /* Compute support of the associated edge, and features of the new position */
1547 if ( !(MMG5_BezierNom(mesh,ip0,ip,step,o,no,to)) ) return 0;
1548
1549 /* Test : check whether all volumes remain positive with new position of the point */
1550 ppt0 = &mesh->point[0];
1551 ppt0->c[0] = o[0];
1552 ppt0->c[1] = o[1];
1553 ppt0->c[2] = o[2];
1554 ppt0->tag = p0->tag;
1555 ppt0->ref = p0->ref;
1556
1557 calold = calnew = DBL_MAX;
1558 for( l=0 ; l<ilistv ; l++ ){
1559 iel = listv[l] / 4;
1560 i0 = listv[l] % 4;
1561 pt = &mesh->tetra[iel];
1562 pt0 = &mesh->tetra[0];
1563 memcpy(pt0,pt,sizeof(MMG5_Tetra));
1564 pt0->v[i0] = 0;
1565 calold = MG_MIN(calold, pt->qual);
1566 callist[l]= MMG5_orcal(mesh,met,0);
1567 if (callist[l] < MMG5_NULKAL) {
1568 return 0;
1569 }
1570 calnew = MG_MIN(calnew,callist[l]);
1571 }
1572 if ((calold < MMG5_EPSOK && calnew <= calold) ||
1573 (calnew < MMG5_EPSOK) || (calnew <= 0.3*calold)) {
1574 return 0;
1575 } else if (improve && calnew < calold) {
1576 return 0;
1577 }
1578
1579 /* Update coordinates and tangent for new point */
1580 if ( PROctree )
1581 MMG3D_movePROctree(mesh, PROctree, ip0, o, p0->c);
1582
1583 p0->c[0] = o[0];
1584 p0->c[1] = o[1];
1585 p0->c[2] = o[2];
1586
1587 p0->n[0] = to[0];
1588 p0->n[1] = to[1];
1589 p0->n[2] = to[2];
1590
1591 for(l=0; l<ilistv; l++){
1592 (&mesh->tetra[listv[l]/4])->qual = callist[l];
1593 (&mesh->tetra[listv[l]/4])->mark = mesh->mark;
1594 }
1595
1596 return 1;
1597}
1598
1615 int ilistv,MMG5_int *lists,int ilists,int improve) {
1616
1617 return MMG3D_movbdycurvept_iso(mesh,met,PROctree,listv,ilistv,lists,ilists,improve,MG_GEO);
1618}
1619
1635 MMG5_pTetra pt,pt1;
1636 MMG5_pPoint ppa,ppb,p1,p2,p3;
1637 int j,iter,maxiter,l,lon;
1638 int64_t list[MMG3D_LMAX+2];
1639 MMG5_int ipb,iadr,i1,i2,i3,iel;
1640 double *mp,coe,qualtet[MMG3D_LMAX+2];
1641 double ax,ay,az,bx,by,bz,nx,ny,nz,dd,len,qual,oldc[3];
1642
1643 assert(k);
1644 assert(ib<4);
1645 pt = &mesh->tetra[k];
1646 ppa = &mesh->point[pt->v[ib]];
1647
1648 if ( (ppa->tag & MG_BDY) || (ppa->tag & MG_REQ) ) {
1649 return 0;
1650 }
1651
1652 iadr = pt->v[ib]*sol->size + 0;
1653 mp = &sol->m[iadr];
1654
1655 /*compute normal*/
1656 i1 = pt->v[MMG5_idir[ib][0]];
1657 i2 = pt->v[MMG5_idir[ib][1]];
1658 i3 = pt->v[MMG5_idir[ib][2]];
1659 p1 = &mesh->point[i1];
1660 p2 = &mesh->point[i2];
1661 p3 = &mesh->point[i3];
1662
1663 ax = p3->c[0] - p1->c[0];
1664 ay = p3->c[1] - p1->c[1];
1665 az = p3->c[2] - p1->c[2];
1666
1667 bx = p2->c[0] - p1->c[0];
1668 by = p2->c[1] - p1->c[1];
1669 bz = p2->c[2] - p1->c[2];
1670
1671 nx = (ay*bz - az*by);
1672 ny = (az*bx - ax*bz);
1673 nz = (ax*by - ay*bx);
1674
1675 dd = sqrt(nx*nx+ny*ny+nz*nz);
1676 dd = 1./dd;
1677 nx *=dd;
1678 ny *=dd;
1679 nz *=dd;
1680 len = 0;
1681 for (j=0; j<3; j++) {
1682 ipb = pt->v[ MMG5_idir[ib][j] ];
1683 ppb = &mesh->point[ipb];
1684
1685 ax = ppb->c[0] - ppa->c[0];
1686 ay = ppb->c[1] - ppa->c[1];
1687 az = ppb->c[2] - ppa->c[2];
1688
1689 dd = mp[0]*ax*ax + mp[3]*ay*ay + mp[5]*az*az \
1690 + 2.0*(mp[1]*ax*ay + mp[2]*ax*az + mp[4]*ay*az);
1691 assert(dd>0);
1692 len += sqrt(dd);
1693 }
1694
1695 dd = 1.0 / (double)3.;
1696 len = 1.0 / len;
1697 len *= dd;
1698 memcpy(oldc,ppa->c,3*sizeof(double));
1699
1700 lon = MMG5_boulevolp(mesh,k,ib,&list[0]);
1701
1702 coe = 1.;
1703 iter = 0;
1704 maxiter = 20;
1705 do {
1706 ppa->c[0] = oldc[0] + coe * nx * len;
1707 ppa->c[1] = oldc[1] + coe * ny * len;
1708 ppa->c[2] = oldc[2] + coe * nz * len;
1709
1710 for (l=0; l<lon; l++) {
1711 iel = list[l] / 4 ;
1712 pt1 = &mesh->tetra[iel];
1713
1714 qual = MMG5_caltet(mesh,sol,pt1);
1715 /*warning if we increase the coefficient (ex 1.4), the mesh quality becomes poor very quickly*/
1716 if ( qual*1.01 <= pt1->qual) break;
1717 qualtet[l] = qual;
1718
1719 }
1720 if ( l >= lon ) break;
1721 coe *= 0.5;
1722 }
1723 while ( ++iter <= maxiter );
1724 if ( iter > maxiter) {
1725 memcpy(ppa->c,oldc,3*sizeof(double));
1726 return 0;
1727 }
1728
1729 for (l=0; l<lon; l++) {
1730 iel = list[l] / 4;
1731 pt1 = &mesh->tetra[iel];
1732 pt1->qual = qualtet[l];
1733 pt1->mark = mesh->mark;
1734 }
1735 return 1;
1736
1737}
1738
1755 MMG5_pTetra pt,pt1;
1756 MMG5_pPoint ppa,ppb,p1,p2,p3;
1757 int j,iter,maxiter,l,lon;
1758 int64_t list[MMG3D_LMAX+2];
1759 MMG5_int ipb,iel,i1,i2,i3;
1760 double coe,crit,qualtet[MMG3D_LMAX+2];
1761 double ax,ay,az,bx,by,bz,nx,ny,nz,dd,len,qual,oldc[3],oldp[3];
1762
1763 assert(k);
1764 assert(ib<4);
1765 pt = &mesh->tetra[k];
1766
1767 ppa = &mesh->point[pt->v[ib]];
1768
1769 if ( ppa->tag & MG_BDY || (ppa->tag & MG_REQ) ) {
1770 return 0;
1771 }
1772
1773 /*compute normal*/
1774 i1 = pt->v[MMG5_idir[ib][0]];
1775 i2 = pt->v[MMG5_idir[ib][1]];
1776 i3 = pt->v[MMG5_idir[ib][2]];
1777 p1 = &mesh->point[i1];
1778 p2 = &mesh->point[i2];
1779 p3 = &mesh->point[i3];
1780
1781 ax = p3->c[0] - p1->c[0];
1782 ay = p3->c[1] - p1->c[1];
1783 az = p3->c[2] - p1->c[2];
1784
1785 bx = p2->c[0] - p1->c[0];
1786 by = p2->c[1] - p1->c[1];
1787 bz = p2->c[2] - p1->c[2];
1788
1789 nx = (ay*bz - az*by);
1790 ny = (az*bx - ax*bz);
1791 nz = (ax*by - ay*bx);
1792
1793 dd = sqrt(nx*nx+ny*ny+nz*nz);
1794 dd = 1./dd;
1795 nx *=dd;
1796 ny *=dd;
1797 nz *=dd;
1798 len = 0;
1799 for (j=0; j<3; j++) {
1800 ipb = pt->v[ MMG5_idir[ib][j] ];
1801 ppb = &mesh->point[ipb];
1802
1803 ax = ppb->c[0] - ppa->c[0];
1804 ay = ppb->c[1] - ppa->c[1];
1805 az = ppb->c[2] - ppa->c[2];
1806
1807 dd = sqrt(ax*ax +ay*ay +az*az);
1808 len += dd;
1809 }
1810
1811 dd = 1.0 / (double)3.;
1812 len *= dd;
1813
1814
1815 memcpy(oldp,ppa->c,3*sizeof(double));
1816 oldc[0] = 1./3.*(p1->c[0]+p2->c[0]+p3->c[0]);
1817 oldc[1] = 1./3.*(p1->c[1]+p2->c[1]+p3->c[1]);
1818 oldc[2] = 1./3.*(p1->c[2]+p2->c[2]+p3->c[2]);
1819
1820 lon = MMG5_boulevolp(mesh,k,ib,&list[0]);
1821
1822 if ( !lon ) return 0;
1823
1824 /*vol crit*/
1825 crit = MMG5_orvol(mesh->point,pt->v);
1826 for (l=1; l<lon; l++) {
1827 iel = list[l] / 4;
1828 pt1 = &mesh->tetra[iel];
1829 if ( pt1->qual < crit) crit = pt1->qual;
1830 }
1831 coe = 0.471404;//2.12132; //3/sqrt(2) : hauteur d'un tetra reg de cote c : c*sqrt(2)/3
1832 iter = 0;
1833 maxiter = 10;
1834 do {
1835 ppa->c[0] = oldc[0] + coe * nx * len;
1836 ppa->c[1] = oldc[1] + coe * ny * len;
1837 ppa->c[2] = oldc[2] + coe * nz * len;
1838 for (l=0; l<lon; l++) {
1839 iel = list[l] / 4;
1840 pt1 = &mesh->tetra[iel];
1841 qual = MMG5_caltet(mesh,sol,pt1);
1842 if ( qual < crit ) {
1843 break;
1844 }
1845 qualtet[l] = qual;
1846
1847 }
1848 if ( l >= lon ) break;
1849 coe *= 0.5;
1850 }
1851 while ( ++iter <= maxiter );
1852 if ( iter > maxiter) {
1853 memcpy(ppa->c,oldp,3*sizeof(double));
1854 return 0;
1855 }
1856
1857 for (l=0; l<lon; l++) {
1858 iel = list[l] / 4;
1859 pt1 = &mesh->tetra[iel];
1860 pt1->qual = qualtet[l];
1861 pt1->mark = mesh->mark;
1862 }
1863 return 1;
1864
1865}
1866
1884 MMG5_pTetra pt,pt1;
1885 MMG5_pPoint ppa,ppb,p1,p2,p3;
1886 int j,iter,maxiter,l,lon;
1887 int64_t list[MMG3D_LMAX+2];
1888 MMG5_int ipb,iadr,iel,i1,i2,i3;
1889 double hp,coe,crit,qualtet[MMG3D_LMAX+2];;
1890 double ax,ay,az,bx,by,bz,nx,ny,nz,dd,len,qual,oldc[3];
1891
1892 assert(k);
1893 assert(ib<4);
1894 pt = &mesh->tetra[k];
1895
1896 ppa = &mesh->point[pt->v[ib]];
1897 if ( (ppa->tag & MG_BDY) || (ppa->tag & MG_REQ) ) {
1898 return 0;
1899 }
1900
1901 iadr = (pt->v[ib])*sol->size;
1902 hp = sol->m[iadr];
1903
1904 /*compute normal*/
1905 i1 = pt->v[MMG5_idir[ib][0]];
1906 i2 = pt->v[MMG5_idir[ib][1]];
1907 i3 = pt->v[MMG5_idir[ib][2]];
1908 p1 = &mesh->point[i1];
1909 p2 = &mesh->point[i2];
1910 p3 = &mesh->point[i3];
1911
1912 ax = p3->c[0] - p1->c[0];
1913 ay = p3->c[1] - p1->c[1];
1914 az = p3->c[2] - p1->c[2];
1915
1916 bx = p2->c[0] - p1->c[0];
1917 by = p2->c[1] - p1->c[1];
1918 bz = p2->c[2] - p1->c[2];
1919
1920 nx = (ay*bz - az*by);
1921 ny = (az*bx - ax*bz);
1922 nz = (ax*by - ay*bx);
1923
1924 dd = sqrt(nx*nx+ny*ny+nz*nz);
1925 dd = 1./dd;
1926 nx *=dd;
1927 ny *=dd;
1928 nz *=dd;
1929 len = 0;
1930 for (j=0; j<3; j++) {
1931 ipb = pt->v[ MMG5_idir[ib][j] ];
1932 ppb = &mesh->point[ipb];
1933
1934 ax = ppb->c[0] - ppa->c[0];
1935 ay = ppb->c[1] - ppa->c[1];
1936 az = ppb->c[2] - ppa->c[2];
1937
1938 dd = sqrt(ax*ax +ay*ay +az*az);
1939 len += dd/hp;
1940 }
1941
1942 dd = 1.0 / (double)3.;
1943 len *= dd;
1944 if(len > 0.) len = 1.0 / len;
1945
1946 memcpy(oldc,ppa->c,3*sizeof(double));
1947
1948 lon = MMG5_boulevolp(mesh,k,ib,&list[0]);
1949
1950 if(!lon) return 0;
1951
1952 /*qual crit*/
1953 crit = pt->qual;
1954 for (l=1; l<lon; l++) {
1955 iel = list[l] / 4;
1956 pt1 = &mesh->tetra[iel];
1957 if ( pt1->qual < crit )
1958 crit = pt1->qual;
1959 }
1960
1961 crit *= 1.01;
1962 coe = 1.;
1963 iter = 0;
1964 maxiter = 20;
1965 do {
1966
1967 ppa->c[0] = oldc[0] + coe * nx * len;
1968 ppa->c[1] = oldc[1] + coe * ny * len;
1969 ppa->c[2] = oldc[2] + coe * nz * len;
1970 for (l=0; l<lon; l++) {
1971 iel = list[l] / 4;
1972 pt1 = &mesh->tetra[iel];
1973 qual = MMG5_caltet(mesh,sol,pt1);
1974 if ( qual < crit ) break;
1975 qualtet[l] = qual;
1976
1977 }
1978 if ( l >= lon ) break;
1979 coe *= 0.5;
1980 }
1981 while ( ++iter <= maxiter );
1982 if ( iter > maxiter) {
1983 memcpy(ppa->c,oldc,3*sizeof(double));
1984 return 0;
1985 }
1986
1987 for (l=0; l<lon; l++) {
1988 iel = list[l] / 4;
1989 pt1 = &mesh->tetra[iel];
1990 pt1->qual = qualtet[l];
1991 pt1->mark = mesh->mark;
1992 }
1993 return 1;
1994
1995}
int ier
MMG5_pMesh MMG5_pSol * sol
if(!ier) exit(EXIT_FAILURE)
MMG5_pMesh * mesh
int MMG3D_movePROctree(MMG5_pMesh mesh, MMG3D_pPROctree q, MMG5_int no, double *newVer, double *oldVer)
Definition: PRoctree_3d.c:225
int MMG3D_bezierInt(MMG5_pBezier pb, double uv[2], double o[3], double no[3], double to[3])
Definition: bezier_3d.c:608
int MMG5_boulevolp(MMG5_pMesh mesh, MMG5_int start, int ip, int64_t *list)
Given a vertex and a tetrahedron, find all tetrahedra in the ball of this vertex.
Definition: boulep_3d.c:57
static double MMG5_lenedg_iso(MMG5_pMesh mesh, MMG5_pSol met, int ia, MMG5_pTetra pt)
static double MMG5_orcal(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int iel)
API headers and documentation for the mmg3d library, for volumetric meshes in 3D.
#define MMG3D_LMAX
Definition: libmmg3d.h:130
#define MMG3D_MOVSTEP
#define MMG3D_LOPTS
static const uint8_t MMG5_arpt[4][3]
arpt[i]: edges passing through vertex i
int MMG5_BezierRidge(MMG5_pMesh mesh, MMG5_int ip0, MMG5_int ip1, double s, double *o, double *no1, double *no2, double *to)
Definition: tools_3d.c:145
int8_t MMG5_chkedg(MMG5_pMesh mesh, MMG5_Tria *pt, int8_t ori, double, double, int)
Definition: mmg3d1.c:363
static const int8_t MMG5_iarf[4][3]
iarf[i]: edges of face opposite to vertex i
static const uint8_t MMG5_iare[6][2]
vertices of extremities of the edges of the tetra
int MMG5_BezierRef(MMG5_pMesh mesh, MMG5_int ip0, MMG5_int ip1, double s, double *o, double *no, double *to)
Definition: tools_3d.c:352
void MMG5_tet2tri(MMG5_pMesh mesh, MMG5_int k, int8_t ie, MMG5_Tria *ptt)
Definition: mmg3d1.c:102
#define MMG3D_LOPTL
int MMG5_BezierNom(MMG5_pMesh mesh, MMG5_int ip0, MMG5_int ip1, double s, double *o, double *no, double *to)
Definition: tools_3d.c:527
static const uint8_t MMG5_idir[4][3]
idir[i]: vertices of face opposite to vertex i
@ MMG5_Tetrahedron
Definition: libmmgtypes.h:233
@ MMG5_Triangle
Definition: libmmgtypes.h:232
#define MG_Tria
#define MG_REQ
#define MG_GEO
#define MMG5_EPSOK
#define MMG5_SQR32
#define MG_EOK(pt)
#define MG_MIN(a, b)
#define MMG5_GAP
#define MG_EDG(tag)
double MMG5_det3pt1vec(double c0[3], double c1[3], double c2[3], double v[3])
Definition: tools.c:920
double MMG5_det4pt(double c0[3], double c1[3], double c2[3], double c3[3])
Definition: tools.c:932
#define MMG5_TAB_RECALLOC(mesh, ptr, initSize, wantedGap, type, message, law)
#define MG_SIN(tag)
#define MMG5_NULKAL
#define MG_Tetra
#define MG_GET(flag, bit)
double MMG5_orvol(MMG5_pPoint point, MMG5_int *v)
Definition: tools.c:951
int MMG5_rotmatrix(double n[3], double r[3][3])
Definition: tools.c:467
#define MG_BDY
#define MG_NOM
#define MMG5_EPSD2
#define MG_REF
int MMG3D_curveEndingPts(MMG5_pMesh mesh, MMG5_int *lists, int ilists, const uint16_t edgTag, MMG5_int ip0, MMG5_int *ip1, MMG5_int *ip2)
Definition: movpt_3d.c:944
int MMG5_movbdynomintpt_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, int64_t *listv, int ilistv, int improve)
Definition: movpt_3d.c:1490
int MMG5_movbdyridpt_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, int64_t *listv, int ilistv, MMG5_int *lists, int ilists, int improve)
Definition: movpt_3d.c:1614
int MMG3D_movnormal_iso(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_int k, int ib)
Definition: movpt_3d.c:1754
int MMG3D_movbdycurvept_chckAndUpdate(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, int64_t *listv, int ilistv, int improve, MMG5_pPoint p0, MMG5_int ip0, uint8_t isrid, double o[3], double no[3], double no2[3], double to[3])
Definition: movpt_3d.c:1056
int MMG3D_rotate_surfacicBall(MMG5_pMesh mesh, MMG5_int *lists, int ilists, MMG5_int ip0, double r[3][3], double *lispoi)
Definition: movpt_3d.c:350
int MMG3D_movv_ani(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_int k, int ib)
Definition: movpt_3d.c:1634
int MMG5_movbdyregpt_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, int64_t *listv, int ilistv, MMG5_int *lists, int ilists, int improveSurf, int improveVol)
Definition: movpt_3d.c:626
int MMG5_movintpt_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, int64_t *list, int ilist, int improve)
Definition: movpt_3d.c:58
static int MMG3D_movbdycurvept_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, int64_t *listv, int ilistv, MMG5_int *lists, int ilists, int improve, const int16_t edgTag)
Definition: movpt_3d.c:1263
static int MMG3D_curveEndingPts_chkEdg(MMG5_pMesh mesh, MMG5_int *lists, int l, MMG5_int ip0, MMG5_int *ipa, MMG5_int *ipb, const uint16_t edgTag, MMG5_int *ip)
Definition: movpt_3d.c:853
int MMG3D_movbdycurvept_newPosForSimu(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_int ip0, MMG5_int ip1, MMG5_int ip2, double ll1old, double ll2old, uint8_t isrid, const double step, double o[3], double no[3], double no2[3], double to[3], const uint16_t edgTag)
Definition: movpt_3d.c:1150
int MMG3D_movv_iso(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_int k, int ib)
Definition: movpt_3d.c:1883
int MMG5_movintptLES_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, MMG5_int *list, int ilist, int improve)
Definition: movpt_3d.c:185
int MMG3D_movbdyregpt_geom(MMG5_pMesh mesh, MMG5_int *lists, const MMG5_int kel, const MMG5_int ip0, double n[3], double lambda[3], double o[3], double no[3])
Definition: movpt_3d.c:483
int MMG5_movbdyrefpt_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, int64_t *listv, int ilistv, MMG5_int *lists, int ilists, int improve)
Definition: movpt_3d.c:1446
int MMG5_movbdynompt_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG3D_pPROctree PROctree, int64_t *listv, int ilistv, MMG5_int *lists, int ilists, int improve)
Definition: movpt_3d.c:1470
int8_t parTyp
Definition: libmmgtypes.h:548
double hmax
Definition: libmmgtypes.h:525
MMG5_pPar par
Definition: libmmgtypes.h:524
double hausd
Definition: libmmgtypes.h:525
MMG mesh structure.
Definition: libmmgtypes.h:613
MMG5_Info info
Definition: libmmgtypes.h:659
MMG5_pPoint point
Definition: libmmgtypes.h:649
MMG5_int mark
Definition: libmmgtypes.h:626
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:650
MMG5_int xp
Definition: libmmgtypes.h:628
MMG5_pTetra tetra
Definition: libmmgtypes.h:651
MMG5_pxTetra xtetra
Definition: libmmgtypes.h:652
MMG5_int xpmax
Definition: libmmgtypes.h:620
Local parameters for a specific entity and reference.
Definition: libmmgtypes.h:263
double hmax
Definition: libmmgtypes.h:265
double hausd
Definition: libmmgtypes.h:266
MMG5_int ref
Definition: libmmgtypes.h:267
int8_t elt
Definition: libmmgtypes.h:268
Structure to store vertices of an MMG mesh.
Definition: libmmgtypes.h:276
double n[3]
Definition: libmmgtypes.h:278
double c[3]
Definition: libmmgtypes.h:277
uint16_t tag
Definition: libmmgtypes.h:290
MMG5_int xp
Definition: libmmgtypes.h:285
MMG5_int ref
Definition: libmmgtypes.h:284
double * m
Definition: libmmgtypes.h:680
Structure to store tetrahedra of an MMG mesh.
Definition: libmmgtypes.h:407
MMG5_int v[4]
Definition: libmmgtypes.h:409
MMG5_int xt
Definition: libmmgtypes.h:413
MMG5_int ref
Definition: libmmgtypes.h:410
MMG5_int mark
Definition: libmmgtypes.h:412
double qual
Definition: libmmgtypes.h:408
Structure to store triangles of a MMG mesh.
Definition: libmmgtypes.h:338
MMG5_int ref
Definition: libmmgtypes.h:341
MMG5_int v[3]
Definition: libmmgtypes.h:340
Structure to store surface vertices of an MMG mesh.
Definition: libmmgtypes.h:300
int8_t nnor
Definition: libmmgtypes.h:303
double n2[3]
Definition: libmmgtypes.h:301
double n1[3]
Definition: libmmgtypes.h:301
Structure to store additional information for the surface tetrahedra of an MMG mesh.
Definition: libmmgtypes.h:425
uint16_t tag[6]
Definition: libmmgtypes.h:432
int8_t ori
Definition: libmmgtypes.h:434