Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
mmg2.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 "mmgcommon_private.h"
37#include "mmgexterns_private.h"
38
46static MMG5_int MMG5_InvMat_key(MMG5_pInvMat pim,int ref) {
47 return (ref - pim->offset);
48}
49
58static int MMG5_InvMat_code(int k,int attr) {
59 return 4*(k+1)+attr;
60}
61
69static int MMG5_InvMat_getIndex(MMG5_pInvMat pim,int ref) {
70 int key = MMG5_InvMat_key(pim,ref);
71 /* The parent index is stored as 4*(k+1) */
72 return (pim->lookup[key] / 4 - 1);
73}
74
84static int MMG5_InvMat_getAttrib(MMG5_pInvMat pim,int ref) {
85 int key = MMG5_InvMat_key(pim,ref);
86 /* The nosplit/split/plus/minus attribute is stored as the rest of the
87 * integer division. */
88 return (pim->lookup[key] % 4);
89}
90
98static int MMG5_InvMat_check(MMG5_pInvMat pim,int key) {
99 return pim->lookup[key] ? 0 : 1;
100}
101
111static void MMG5_InvMat_error(MMG5_pInvMat pim,int ref,int k) {
112 fprintf(stderr,"\n ## Warning: Overwrite material reference %d"
113 " (from LSReferences line %d) with another entry from LSReferences line %d."
114 ,ref,MMG5_InvMat_getIndex(pim,ref)+1,k+1);
115 fprintf(stderr,"\n Check your LSReferences table: if possible,"
116 " each material reference should be unique,\n"
117 " if not possible, you may"
118 " encounter unexpected issues (wrong domain mapping or erroneous"
119 " detection of non-manifold level-set)!\n");
120}
121
130 MMG5_pMat pm;
131 int key;
132
133 /* Get material */
134 pm = &mesh->info.mat[k];
135
137 key = MMG5_InvMat_key(pim,pm->ref);
138 if( !MMG5_InvMat_check(pim,key) ) {
139 MMG5_InvMat_error(pim,pm->ref,k);
140 }
141 pim->lookup[key] = MMG5_InvMat_code(k,pm->dospl);
142
150 if( pm->dospl ) {
151 key = MMG5_InvMat_key(pim,pm->rin);
152 if( !MMG5_InvMat_check(pim,key) ) {
153 MMG5_InvMat_error(pim,pm->rin,k);
154 }
155 pim->lookup[key] = MMG5_InvMat_code(k,MG_MINUS);
156
157 key = MMG5_InvMat_key(pim,pm->rex);
158 if( !MMG5_InvMat_check(pim,key) ) {
159 MMG5_InvMat_error(pim,pm->rex,k);
160 }
161 pim->lookup[key] = MMG5_InvMat_code(k,MG_PLUS);
162 }
163
164 return 1;
165}
166
177static int MMG5_InvMat_getParent(MMG5_pMesh mesh,MMG5_pInvMat pim,MMG5_int ref,MMG5_int *pref) {
178 MMG5_pMat pm;
179 int k;
180
181 /* The parent index */
182 k = MMG5_InvMat_getIndex(pim,ref);
183
184 /* Material not found in the table */
185 if( k == -1 ) {
186 fprintf(stderr,"\n ## Warning: %s: material %" MMG5_PRId " not found in table.\n",
187 __func__,ref);
188 fprintf(stderr," Please ensure that you provide all mesh"
189 " references in the material map\n"
190 " (that is, the whole list of"
191 " surface materials in lssurf mode,\n"
192 " and the whole list of domain"
193 " materials in ls mode).\n" );
194 return 0;
195 }
196
197 /* Get the material in the lookup table and return the parent reference */
198 pm = &mesh->info.mat[k];
199 *pref = pm->ref;
200 return 1;
201}
202
213int MMG5_getStartRef(MMG5_pMesh mesh,MMG5_int ref,MMG5_int *pref) {
214 MMG5_pInvMat pim;
215
216 /* No multi-materials nor single material reference preservation */
217 if( !mesh->info.nmat ) {
218 *pref = 0;
219 return 1;
220 }
221
222 /* Get parent of material */
223 pim = &mesh->info.invmat;
224
225 /* Return 0 if the material does not exist, 1 otherwise */
226 if( !MMG5_InvMat_getParent(mesh,pim,ref,pref) )
227 return 0;
228 else
229 return 1;
230}
231
239 MMG5_int ref,pref;
240
241 /* Scan all references in the table limits, some may not exist */
242 for( ref = pim->offset; ref < pim->offset + pim->size; ref++ ) {
243 if( !MMG5_InvMat_getParent(mesh,pim,ref,&pref) ) continue;
244 printf("%" MMG5_PRId " (%" MMG5_PRId "): %" MMG5_PRId " %d\n",ref,
245 MMG5_InvMat_key(pim,ref),pref,
246 MMG5_InvMat_getAttrib(pim,ref));
247 }
248}
249
327 MMG5_pMat pm;
328 MMG5_pInvMat pim;
329 int k;
330 MMG5_int refmax,refmin;
331
332 /* Nothing to do if no multi-material option */
333 if( !mesh->info.nmat ) return 1;
334
335 /* Error if all the materials have not been set */
336 if( mesh->info.nmati < mesh->info.nmat ) {
337 fprintf(stderr,"\n ## Error: %s: Only %d materials out of %d have been set.\n",
338 __func__,mesh->info.nmati,mesh->info.nmat);
339 return 0;
340 }
341
342 /* Get pointer to the structure */
343 pim = &mesh->info.invmat;
344
345 /* Initialize the max and min reference */
346 refmax = 0;
347
348 if ( sizeof(MMG5_int) == 8 ) {
349 refmin = LONG_MAX;
350 }
351 else {
352 refmin = INT_MAX;
353 }
354
355 /* Look for the max/min reference provided in material table */
356 for( k = 0; k < mesh->info.nmat; k++ ) {
357 pm = &mesh->info.mat[k];
358 /* Update max and min val for original ref */
359 if( pm->ref > refmax ) refmax = pm->ref;
360 if( pm->ref < refmin ) refmin = pm->ref;
361 if( !pm->dospl ) continue;
362 /* Update max and min val with interior ref */
363 if( pm->rin > refmax ) refmax = pm->rin;
364 if( pm->rin < refmin ) refmin = pm->rin;
365 /* Update max and min val with exterior ref */
366 if( pm->rex > refmax ) refmax = pm->rex;
367 if( pm->rex < refmin ) refmin = pm->rex;
368 }
369
370 /* Look for the max/min reference of tetra, triangles and edges provided
371 * inside the mesh (worst case to avoid memory error when checking the
372 * the inverse map). Looking at vertices is useless as
373 * we will never check for the mapping of reference of vertices */
374 for ( k=1; k<=mesh->ne; ++k ) {
375 if( mesh->tetra[k].ref > refmax ) refmax = mesh->tetra[k].ref;
376 if( mesh->tetra[k].ref < refmin ) refmin = mesh->tetra[k].ref;
377 }
378 for ( k=1; k<=mesh->nt; ++k ) {
379 if( mesh->tria[k].ref > refmax ) refmax = mesh->tria[k].ref;
380 if( mesh->tria[k].ref < refmin ) refmin = mesh->tria[k].ref;
381 }
382 for ( k=1; k<=mesh->na; ++k ) {
383 if( mesh->edge[k].ref > refmax ) refmax = mesh->edge[k].ref;
384 if( mesh->edge[k].ref < refmin ) refmin = mesh->edge[k].ref;
385 }
386
387 /* Get span of the lookup table */
388 pim->offset = refmin;
389 pim->size = refmax - refmin + 1;
390 assert( pim->size > 0 );
391
392 /* Allocate lookup table */
393 MMG5_ADD_MEM(mesh,pim->size*sizeof(int),"materials lookup table",return 0);
394 MMG5_SAFE_CALLOC(pim->lookup,pim->size,int,return 0);
395
396 /* Fill lookup table */
397 for( k = 0; k < mesh->info.nmat; k++ ) {
398 if( !MMG5_InvMat_set(mesh,pim,k) )
399 return 0;
400 }
401
402 // MMG5_InvMat_print(mesh,pim);
403 return 1;
404}
405
417int MMG5_isSplit(MMG5_pMesh mesh,MMG5_int ref,MMG5_int *refint,MMG5_int *refext) {
418 MMG5_pInvMat pim;
419 MMG5_pMat pm;
420 int k;
421
422 /* Default case: split with references MG_MINUS, MG_PLUS */
423 if( !mesh->info.nmat ) {
424 *refint = MG_MINUS;
425 *refext = MG_PLUS;
426 return 1;
427 }
428
429 /* Check in the info->mat table if reference ref is supplied by the user */
430 pim = &mesh->info.invmat;
431 k = MMG5_InvMat_getIndex(pim,ref);
432
433 assert( k != -1 );
434 pm = &mesh->info.mat[k];
435
436 if ( !pm->dospl ) {
437 return 0;
438 } else {
439 *refint = pm->rin;
440 *refext = pm->rex;
441 return 1;
442 }
443}
444
453int MMG5_isNotSplit(MMG5_pMesh mesh,MMG5_int ref) {
454 MMG5_pInvMat pim;
455
456 /* Split material by default if not in multi-material mode */
457 if( !mesh->info.nmat ) return 0;
458
459 /* Look in the table otherwise */
460 pim = &mesh->info.invmat;
461 if( !MMG5_InvMat_getAttrib(pim,ref) )
462 return 0;
463 else
464 return 1;
465
466}
467
477int MMG5_isLevelSet(MMG5_pMesh mesh,MMG5_int ref0,MMG5_int ref1) {
478 MMG5_pInvMat pim;
479 int8_t found0,found1;
480
481 /* Check whether multimaterial case or not */
482 if( mesh->info.nmat ) {
483 /* Retrieve levelset information from the lookup table */
484 pim = &mesh->info.invmat;
485 found0 = MMG5_InvMat_getAttrib(pim,ref0);
486 found1 = MMG5_InvMat_getAttrib(pim,ref1);
487
488 if( (found0+found1) == (MG_MINUS+MG_PLUS) ) return 1;
489 else return 0;
490
491 } else {
492 /* Single material, check references directly */
493 if( ( ref0 == MG_MINUS && ref1 == MG_PLUS ) ||
494 ( ref1 == MG_MINUS && ref0 == MG_PLUS ) ) return 1;
495 else return 0;
496 }
497}
498
509 MMG5_pTria pt,pt1;
510 MMG5_pPoint p0;
511 double v1,v2,*tmp;
512 MMG5_int k,kk,iel,ns,nc,ip,ip1,ip2,npl,nmn;
513 int ilist;
514 int8_t i,j,j1,j2;
515 MMG5_int list[MMG5_TRIA_LMAX+2];
516
517 /* Allocate memory for tmp */
518 MMG5_ADD_MEM(mesh,(mesh->npmax+1)*sizeof(double),"temporary table",
519 fprintf(stderr," Exit program.\n");
520 return 0);
521 MMG5_SAFE_CALLOC(tmp,mesh->npmax+1,double,return 0);
522
523 /* Reset point flags */
524 for (k=1; k<=mesh->np; k++)
525 mesh->point[k].flag = 0;
526
527 /* Snap values of sol that are close to 0 to 0 exactly */
528 ns = nc = 0;
529 for (k=1; k<=mesh->np; k++) {
530 p0 = &mesh->point[k];
531 if ( !MG_VOK(p0) ) continue;
532 if ( fabs(sol->m[k]) < MMG5_EPS ) {
533 tmp[k] = sol->m[k];
534 p0->flag = 1;
535 sol->m[k] = 0.0;
536 ns++;
537 }
538 }
539
540 /* Check that the snapping process has not led to a nonmanifold situation */
541 for (k=1; k<=mesh->nt; k++) {
542 pt = &mesh->tria[k];
543 if ( !MG_EOK(pt) ) continue;
544 for (i=0; i<3; i++) {
545 ip = pt->v[i];
546 ip1 = pt->v[MMG5_inxt2[i]];
547 ip2 = pt->v[MMG5_iprv2[i]];
548
549 p0 = &mesh->point[ip];
550 v1 = sol->m[ip1];
551 v2 = sol->m[ip2];
552
553 /* Catch a snapped point by a triangle where there is a sign change: use
554 * the same convention than in ismaniball to evaluate sign changes. If
555 * travelled in direct sense from a triangle, an edge is considered
556 * without sign change if first vertex is 0. It has a sign change if
557 * second vertex is 0 or if we have 2 vertices with different signs
558 * (otherwise a 0 vertex leads to count 2 sign changes instead of one). */
559 int smsgn = ((fabs(v2) < MMG5_EPS) || MG_SMSGN(v1,v2)) ? 1 : 0;
560 if ( p0->flag && !smsgn ) {
561 if ( !MMG5_ismaniball(mesh,sol,k,i) ) {
562 if ( tmp[ip] < 0.0 )
563 sol->m[ip] = -100.0*MMG5_EPS;
564 else
565 sol->m[ip] = 100.0*MMG5_EPS;
566 nc++;
567 }
568 p0->flag = 0;
569 }
570 }
571 }
572
573 /* Check that the ls function does not show isolated spots with 0 values (without sign changes) */
574 for (k=1; k<=mesh->nt; k++) {
575 pt = &mesh->tria[k];
576 if ( !MG_EOK(pt) ) continue;
577 for (i=0; i<3; i++) {
578 ip = pt->v[i];
579 if ( fabs(sol->m[ip]) >= MMG5_EPS ) continue;
580 npl = nmn = 0;
581 int8_t opn; //unused
582 ilist = MMG5_boulet(mesh,k,i,list,1,&opn);
583 for(kk=0; kk<ilist; kk++) {
584 iel = list[kk] / 3;
585 j = list[kk] % 3;
586 j1 = MMG5_inxt2[j];
587 j2 = MMG5_iprv2[i];
588 pt1 = &mesh->tria[iel];
589 ip1 = pt1->v[j1];
590 ip2 = pt1->v[j2];
591 if ( sol->m[ip1] >= MMG5_EPS ) npl = 1;
592 else if ( sol->m[ip1] <= -MMG5_EPS ) nmn = 1;
593
594 if ( sol->m[ip2] >= MMG5_EPS ) npl = 1;
595 else if ( sol->m[ip2] <= -MMG5_EPS ) nmn = 1;
596 }
597
598 if ( npl == 1 && nmn == 0 )
599 sol->m[ip] = 100.0*MMG5_EPS;
600 else if ( npl == 0 && nmn == 1 )
601 sol->m[ip] = -100.0*MMG5_EPS;
602 }
603 }
604
605 if ( (abs(mesh->info.imprim) > 5 || mesh->info.ddebug) && ns+nc > 0 )
606 fprintf(stdout," %8" MMG5_PRId " points snapped, %" MMG5_PRId " corrected\n",ns,nc);
607
608 /* memory free */
610
611 return 1;
612}
613
628int MMG5_ismaniball(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_int start, int8_t istart) {
629 MMG5_pTria pt;
630 double v1, v2;
631 MMG5_int refstart,*adja,k,ip1,ip2,end1;
632 int8_t i,i1,smsgn;
633 static int8_t mmgWarn=0;
634
635 k = start;
636 refstart = mesh->tria[k].ref;
637 i = MMG5_inxt2[istart];
638
639 /* First loop: stop if an external boundary, or a change in signs (or a 0) is met
640 recall that MG_SMGSGN(a,b) = 1 provided a*b >0 */
641 do{
642 adja = &mesh->adja[3*(k-1)+1];
643 k = adja[i] / 3;
644 i1 = adja[i] % 3;
645 i = MMG5_iprv2[i1];
646
647 if ( k==0 ) break;
648
649 pt = &mesh->tria[k];
650
651 ip1 = pt->v[i1];
652 ip2 = pt->v[i];
653
654 v1 = sol->m[ip1];
655 v2 = sol->m[ip2];
656
657 if ( (fabs(v1) < MMG5_EPS) && (fabs(v2) < MMG5_EPS) ) {
658 /* Do not authorize a snap that leads to a triangle with only 0 vertices */
659 return 0;
660 }
661
662 /* Authorize change of references only provided the boundary reference is mesh->info.isoref */
663 if ( pt->ref != refstart && pt->edg[i1] != mesh->info.isoref ) {
664 smsgn = 0;
665 k = 0;
666 } else {
667 /* Evaluation of sign change using following convention: If
668 * travelled in direct sense from a triangle, an edge is considered
669 * without sign change if first vertex is 0. It has a sign change if
670 * second vertex is 0 or if we have 2 vertices with different signs
671 * (otherwise a 0 vertex leads to count 2 sign changes instead of one). */
672 smsgn = (fabs(v1) < MMG5_EPS) || ( (fabs(v2) > MMG5_EPS) && MG_SMSGN(v1,v2) ) ? 1 : 0;
673 }
674 }
675 while ( smsgn && (k != start) );
676
677 if ( k==start ) {
678 /* Complete ball has been travelled without crossing a boundary or finding a
679 * sign change: we are in the special case where v1 = v2 = v[istart] = 0 in
680 * tria start. In this case, test MG_SMSGN(v1,v2) returns 0 while smsgn is
681 * computed to 1, which is non consistent. */
682 assert ( smsgn );
683 return 0;
684 }
685
686 end1 = k;
687 k = start;
688 i = MMG5_iprv2[istart];
689
690 /* Second loop: same travel in the opposite sense */
691 do{
692 adja = &mesh->adja[3*(k-1)+1];
693 k = adja[i] / 3;
694 i1 = adja[i] % 3;
695 i = MMG5_inxt2[i1];
696
697 if ( k==0 ) break;
698
699 pt = &mesh->tria[k];
700 ip1 = pt->v[i1];
701 ip2 = pt->v[i];
702
703 v1 = sol->m[ip1];
704 v2 = sol->m[ip2];
705
706 if ( (fabs(v1) < MMG5_EPS) && (fabs(v2) < MMG5_EPS) ) {
707 /* Do not authorize a snap that leads to a triangle with only 0 vertices */
708 return 0;
709 }
710
711 if ( pt->ref != refstart && pt->edg[i1] != mesh->info.isoref ) {
712 smsgn = 0;
713 k = 0;
714 } else {
715 /* Evaluation of sign change using following convention: If
716 * travelled in undirect sense from a triangle, an edge is considered
717 * without sign change if second vertex is 0. It has a sign change if
718 * first vertex is 0 or if we have 2 vertices with different signs
719 * (it allows to evaluate the same splitted edges than the first loop). */
720 smsgn = (fabs(v2) < MMG5_EPS) || ( (fabs(v1) > MMG5_EPS) && MG_SMSGN(v1,v2) ) ? 1 : 0;
721 }
722 }
723 while ( smsgn && (k != start) );
724
725 assert ( k!=start );
726
727 /* If first stop was due to an external boundary, the second one must too
728 (k==end1==0); else, the final triangle for the first travel must be that of
729 the second one */
730 if ( k != end1 ) {
731 if ( !mmgWarn ) {
732 mmgWarn = 1;
733 fprintf(stderr,"\n ## Warning: %s: unsnap at least 1 point "
734 "(point %" MMG5_PRId " in tri %" MMG5_PRId ").\n",__func__,
735 MMG5_indPt(mesh,mesh->tria[start].v[istart]),MMG5_indElt(mesh,start));
736 }
737 return 0;
738 }
739 return 1;
740}
741
752static inline
753double MMG5_voltri(MMG5_pMesh mesh,MMG5_int ip0,MMG5_int ip1,MMG5_int ip2) {
754 MMG5_pPoint p0,p1,p2;
755 double vol;
756
757 p0 = &mesh->point[ip0];
758 p1 = &mesh->point[ip1];
759 p2 = &mesh->point[ip2];
760
761 vol = (p1->c[0]-p0->c[0])*(p2->c[1]-p0->c[1]) - (p1->c[1]-p0->c[1])*(p2->c[0]-p0->c[0]);
762 vol = 0.5*fabs(vol);
763
764 return vol;
765}
766
779static inline
780double MMG5_vfrac(MMG5_pMesh mesh,MMG5_pSol sol,MMG5_int k,int pm) {
781 MMG5_pTria pt;
782 MMG5_pPoint ppt[3];
783 double v[3],vfp,vfm,lam,area,eps,o1[2],o2[2];
784 MMG5_int ip[3],nplus,nminus,nzero;
785 int8_t i,i0,i1,i2,imin1,iplus1,iz;
786
787 eps = MMG5_EPS*MMG5_EPS;
788 pt = &mesh->tria[k];
789
790 ip[0] = pt->v[0];
791 ip[1] = pt->v[1];
792 ip[2] = pt->v[2];
793
794 ppt[0] = &mesh->point[ip[0]];
795 ppt[1] = &mesh->point[ip[1]];
796 ppt[2] = &mesh->point[ip[2]];
797
798 v[0] = sol->m[ip[0]];
799 v[1] = sol->m[ip[1]];
800 v[2] = sol->m[ip[2]];
801
802 /* Identify number of zero, positive and negative vertices, and corresponding indices */
803 nplus = nminus = nzero = 0;
804 imin1 = iplus1 = iz = -1;
805
806 for (i=0; i<3; i++) {
807 if ( fabs(v[i]) < eps ) {
808 nzero++;
809 if ( iz < 0 ) iz = i;
810 }
811 else if ( v[i] >= eps ) {
812 nplus++;
813 if ( iplus1 < 0 ) iplus1 = i;
814 }
815 else {
816 nminus++;
817 if ( imin1 < 0 ) imin1 = i;
818 }
819 }
820
821 /* Degenerate case */
822 if ( nzero == 3 ) return 0.0;
823
824 /* Whole triangle is positive */
825 if ( nminus == 0 ) {
826 vfp = (ppt[1]->c[0]-ppt[0]->c[0])*(ppt[2]->c[1]-ppt[0]->c[1]) - (ppt[1]->c[1]-ppt[0]->c[1])*(ppt[2]->c[0]-ppt[0]->c[0]);
827 vfp = 0.5*fabs(vfp);
828 if ( pm == 1 ) return vfp;
829 else return 0.0;
830 }
831
832 /* Whole triangle is negative */
833 if ( nplus == 0 ) {
834 vfm = (ppt[1]->c[0]-ppt[0]->c[0])*(ppt[2]->c[1]-ppt[0]->c[1]) - (ppt[1]->c[1]-ppt[0]->c[1])*(ppt[2]->c[0]-ppt[0]->c[0]);
835 vfm = 0.5*fabs(vfm);
836 if ( pm == -1 ) return vfm;
837 else return 0.0;
838 }
839
840 /* Exactly one vertex is negative */
841 if ( nminus == 1 ) {
842 i0 = imin1;
843 i1 = MMG5_inxt2[i0];
844 i2 = MMG5_iprv2[i0];
845
846 lam = v[i0] / (v[i0]-v[i1]);
847 o1[0] = ppt[i0]->c[0] + lam*(ppt[i1]->c[0]-ppt[i0]->c[0]);
848 o1[1] = ppt[i0]->c[1] + lam*(ppt[i1]->c[1]-ppt[i0]->c[1]);
849
850 lam = v[i0] / (v[i0]-v[i2]);
851 o2[0] = ppt[i0]->c[0] + lam*(ppt[i2]->c[0]-ppt[i0]->c[0]);
852 o2[1] = ppt[i0]->c[1] + lam*(ppt[i2]->c[1]-ppt[i0]->c[1]);
853
854 vfm = (o1[0]-ppt[i0]->c[0])*(o2[1]-ppt[i0]->c[1]) - (o1[1]-ppt[i0]->c[1])*(o2[0]-ppt[i0]->c[0]);
855 vfm = 0.5*fabs(vfm);
856
857 if ( pm == -1 ) return vfm;
858 else {
859 area = (ppt[1]->c[0]-ppt[0]->c[0])*(ppt[2]->c[1]-ppt[0]->c[1]) - (ppt[1]->c[1]-ppt[0]->c[1])*(ppt[2]->c[0]-ppt[0]->c[0]);
860 area = 0.5*fabs(area);
861 vfp = area-vfm;
862 return vfp;
863 }
864 }
865
866 /* Exactly one vertex is positive */
867 if ( nplus == 1 ) {
868 i0 = iplus1;
869 i1 = MMG5_inxt2[i0];
870 i2 = MMG5_iprv2[i0];
871
872 lam = v[i0] / (v[i0]-v[i1]);
873 o1[0] = ppt[i0]->c[0] + lam*(ppt[i1]->c[0]-ppt[i0]->c[0]);
874 o1[1] = ppt[i0]->c[1] + lam*(ppt[i1]->c[1]-ppt[i0]->c[1]);
875
876 lam = v[i0] / (v[i0]-v[i2]);
877 o2[0] = ppt[i0]->c[0] + lam*(ppt[i2]->c[0]-ppt[i0]->c[0]);
878 o2[1] = ppt[i0]->c[1] + lam*(ppt[i2]->c[1]-ppt[i0]->c[1]);
879
880 vfp = (o1[0]-ppt[i0]->c[0])*(o2[1]-ppt[i0]->c[1]) - (o1[1]-ppt[i0]->c[1])*(o2[0]-ppt[i0]->c[0]);
881 vfp = 0.5*fabs(vfp);
882
883 if ( pm == 1 ) return vfp;
884 else {
885 area = (ppt[1]->c[0]-ppt[0]->c[0])*(ppt[2]->c[1]-ppt[0]->c[1]) - (ppt[1]->c[1]-ppt[0]->c[1])*(ppt[2]->c[0]-ppt[0]->c[0]);
886 area = 0.5*fabs(area);
887 vfm = area-vfp;
888 return vfm;
889 }
890 }
891
892 /* Should not pass here */
893 return 0.0;
894}
895
897static inline
898int MMG5_isbr(MMG5_pMesh mesh,MMG5_int ref) {
899 MMG5_int k;
900
901 for(k=0; k<mesh->info.nbr; k++)
902 if ( ref == mesh->info.br[k] ) return 1;
903
904 return 0;
905}
906
918 MMG5_pTria pt,pt1,pt2;
919 double volc,voltot,v0,v1,v2;
920 MMG5_int k,kk,l,ll,ncp,ncm,ip0,ip1,ip2,cur,ipile,*pile,*adja,base;
921 int8_t i,i1,i2,onbr;
922
923 ncp = 0;
924 ncm = 0;
925
926 /* Erase triangle flags */
927 for (k=1; k<=mesh->nt; k++) mesh->tria[k].flag = 0;
928
929 /* Calculate volume of the total mesh */
930 voltot = 0.0;
931 for (k=1; k<=mesh->nt; k++) {
932 pt = &mesh->tria[k];
933 if ( !MG_EOK(pt) ) continue;
934 ip0 = pt->v[0];
935 ip1 = pt->v[1];
936 ip2 = pt->v[2];
937 voltot += MMG5_voltri(mesh,ip0,ip1,ip2);
938 }
939
940 /* Memory allocation for pile */
941 MMG5_ADD_MEM(mesh,(mesh->nt+1)*sizeof(MMG5_int),"temporary table",
942 printf(" Exit program.\n");
943 return 0);
944 MMG5_SAFE_CALLOC(pile,mesh->nt+1,MMG5_int,return 0);
945
946 /* Investigate only positive connected components */
947 base = ++mesh->base;
948
949 for (k=1; k<=mesh->nt; k++) {
950 ipile = 0;
951 volc = 0.0;
952 pt = &mesh->tria[k];
953 if ( !MG_EOK(pt) ) continue;
954 if ( pt->flag == base ) continue;
955
956 /* Checks signs of the LS function at the 3 vertices of pt */
957 ip0 = pt->v[0];
958 ip1 = pt->v[1];
959 ip2 = pt->v[2];
960
961 v0 = sol->m[ip0];
962 v1 = sol->m[ip1];
963 v2 = sol->m[ip2];
964
965 if ( v0 <= 0.0 && v1 <= 0.0 && v2 <= 0.0 ) continue;
966
967 /* Add triangle to pile if one vertex is > 0 */
968 pt->flag = base;
969 pile[ipile] = k;
970 ipile++;
971 if ( ipile > mesh->nt ) {
972 fprintf(stderr,"\n ## Problem in length of pile; function rmc.\n"
973 " Check that the level-set intersect the mesh.\n"
974 " Exit program.\n");
975
976 return 0;
977 }
978
979 /* Pile up all the positive connected component attached to the first triangle */
980 cur = 0;
981 do {
982 kk = pile[cur];
983 pt1 = &mesh->tria[kk];
984
985 /* Add local volume fraction of the positive subdomain to volc */
986 volc += MMG5_vfrac(mesh,sol,kk,1);
987
988 /* Add adjacent triangles to kk via positive vertices to the pile, if need be */
989 adja = &mesh->adja[3*(kk-1)+1];
990 for (i=0; i<3; i++) {
991 ip0 = pt1->v[i];
992 if ( sol->m[ip0] <= 0.0 ) continue;
993
994 i1 = MMG5_inxt2[i];
995 i2 = MMG5_inxt2[i1];
996
997 /* First neighbor of positive vertex i */
998 ll = adja[i1] / 3;
999 if ( ll ) {
1000 pt2 = &mesh->tria[ll];
1001 if ( pt2->flag != base ) {
1002 pt2->flag = base;
1003 pile[ipile] = ll;
1004 ipile++;
1005 if ( ipile > mesh->nt ) {
1006 fprintf(stderr,"\n ## Problem in length of pile; function rmc. Exit program.\n");
1007 return 0;
1008 }
1009 }
1010 }
1011
1012 /* Second neighbor of positive vertex i */
1013 ll = adja[i2] / 3;
1014 if ( ll ) {
1015 pt2 = &mesh->tria[ll];
1016 if ( pt2->flag != base ) {
1017 pt2->flag = base;
1018 pile[ipile] = ll;
1019 ipile++;
1020 if ( ipile > mesh->nt ) {
1021 fprintf(stderr,"\n ## Problem in length of pile; function rmc. Exit program.\n");
1022 return 0;
1023 }
1024 }
1025 }
1026 }
1027 }
1028 while ( ++cur < ipile );
1029
1030 /* Remove connected component if its volume is too small */
1031 if ( volc < mesh->info.rmc*voltot ) {
1032 for (l=0; l<ipile; l++) {
1033 pt1 = &mesh->tria[pile[l]];
1034 for (i=0; i<3; i++) {
1035 ip0 = pt1->v[i];
1036 if ( sol->m[ip0] > 0.0 ) sol->m[ip0] = -100*MMG5_EPS;
1037 }
1038 }
1039 ncp++;
1040 }
1041
1042 }
1043
1044 /* Investigate only negative connected components */
1045 base = ++mesh->base;
1046
1047 for (k=1; k<=mesh->nt; k++) {
1048 ipile = 0;
1049 volc = 0.0;
1050 pt = &mesh->tria[k];
1051 if ( !MG_EOK(pt) ) continue;
1052 if ( pt->flag == base ) continue;
1053
1054 /* Checks signs of the LS function at the 3 vertices of pt */
1055 ip0 = pt->v[0];
1056 ip1 = pt->v[1];
1057 ip2 = pt->v[2];
1058
1059 v0 = sol->m[ip0];
1060 v1 = sol->m[ip1];
1061 v2 = sol->m[ip2];
1062
1063 if ( v0 >= 0.0 && v1 >= 0.0 && v2 >= 0.0 ) continue;
1064
1065 /* Pile up all the negative connected component attached to the first triangle */
1066 pt->flag = base;
1067 pile[ipile] = k;
1068 ipile++;
1069 if ( ipile > mesh->nt ) {
1070 fprintf(stderr,"\n ## Problem in length of pile; function rmc. Exit program.\n");
1071 return 0;
1072 }
1073
1074 cur = 0;
1075 do {
1076 kk = pile[cur];
1077 pt1 = &mesh->tria[kk];
1078
1079 /* Add local volume fraction of the negative subdomain to volc */
1080 volc += MMG5_vfrac(mesh,sol,kk,-1);
1081
1082 /* Add adjacent triangles to kk via negative vertices to the pile, if need be */
1083 adja = &mesh->adja[3*(kk-1)+1];
1084 for (i=0; i<3; i++) {
1085 ip0 = pt1->v[i];
1086 if ( sol->m[ip0] >= 0.0 ) continue;
1087
1088 i1= MMG5_inxt2[i];
1089 i2 = MMG5_inxt2[i1];
1090
1091 /* First neighbor of negative vertex i */
1092 ll = adja[i1] / 3;
1093 if ( ll ) {
1094 pt2 = &mesh->tria[ll];
1095 if ( pt2->flag != base ) {
1096 pt2->flag = base;
1097 pile[ipile] = ll;
1098 ipile++;
1099 if ( ipile > mesh->nt ) {
1100 fprintf(stderr,"\n ## Problem in length of pile; function rmc. Exit program.\n");
1101 return 0;
1102 }
1103 }
1104 }
1105
1106 /* Second neighbor of negative vertex i */
1107 ll = adja[i2] / 3;
1108 if ( ll ) {
1109 pt2 = &mesh->tria[ll];
1110 if ( pt2->flag != base ) {
1111 pt2->flag = base;
1112 pile[ipile] = ll;
1113 ipile++;
1114 if ( ipile > mesh->nt ) {
1115 fprintf(stderr,"\n ## Problem in length of pile; function rmc. Exit program.\n");
1116 return 0;
1117 }
1118 }
1119 }
1120
1121 }
1122 }
1123 while ( ++cur < ipile );
1124
1125 /* Remove connected component if its volume is too small */
1126 if ( volc < mesh->info.rmc*voltot ) {
1127 for (l=0; l<ipile; l++) {
1128 pt1 = &mesh->tria[pile[l]];
1129 for (i=0; i<3; i++) {
1130 ip0 = pt1->v[i];
1131 if ( sol->m[ip0] < 0.0 ) sol->m[ip0] = 100*MMG5_EPS;
1132 }
1133 }
1134 ncm++;
1135 }
1136
1137 /* Remove connected component if it is not attached to one base reference */
1138 if ( mesh->info.nbr ) {
1139 onbr = 0;
1140 for (l=0; l<ipile; l++) {
1141 pt1 = &mesh->tria[pile[l]];
1142 for (i=0; i<3; i++) {
1143 if ( MMG5_isbr(mesh,pt1->edg[i]) ) {
1144 i1 = MMG5_inxt2[i];
1145 i2 = MMG5_inxt2[i1];
1146 ip1 = pt1->v[i1];
1147 if ( sol->m[ip1] < 0.0 ) {
1148 onbr = 1;
1149 break;
1150 }
1151 ip2 = pt1->v[i2];
1152 if ( sol->m[ip2] < 0.0 ) {
1153 onbr = 1;
1154 break;
1155 }
1156 }
1157 }
1158 if ( onbr ) break;
1159 }
1160
1161 if ( !onbr ) {
1162 for (l=0; l<ipile; l++) {
1163 pt1 = &mesh->tria[pile[l]];
1164 for (i=0; i<3; i++) {
1165 ip0 = pt1->v[i];
1166 if ( sol->m[ip0] < 0.0 ) sol->m[ip0] = 100*MMG5_EPS;
1167 }
1168 }
1169 ncm++;
1170 }
1171 }
1172
1173 }
1174
1175 /* Erase triangle flags */
1176 for (k=1; k<=mesh->nt; k++) mesh->tria[k].flag = 0;
1177
1178 /* Release memory */
1179 MMG5_DEL_MEM(mesh,pile);
1180
1181 if ( mesh->info.imprim > 0 || mesh->info.ddebug ) {
1182 printf("\n *** Removed %" MMG5_PRId " positive parasitic bubbles and %" MMG5_PRId " negative parasitic bubbles\n",ncp,ncm);
1183 }
1184
1185 return(1);
1186}
1187
1195 MMG5_pTria pt;
1196 MMG5_pPoint p0;
1197 MMG5_int ref,k;
1198 int8_t i;
1199
1200 for (k=1; k<=mesh->nt; k++) {
1201 pt = &mesh->tria[k];
1202 if ( !pt->v[0] ) continue;
1203
1204 for (i=0; i<3; i++) {
1205 p0 = &mesh->point[pt->v[i]];
1206 if ( pt->edg[i] == mesh->info.isoref ) pt->edg[i] = 0;
1207 if ( p0->ref == mesh->info.isoref ) p0->ref = 0;
1208 }
1209 }
1210
1211 /* Reset the triangle references to their initial distribution */
1212 for (k=1; k<=mesh->nt; k++) {
1213 pt = &mesh->tria[k];
1214 if ( !pt->v[0] ) continue;
1215 if( !MMG5_getStartRef(mesh,pt->ref,&ref) ) return 0;
1216 pt->ref = ref;
1217 }
1218
1219 return 1;
1220}
1221
1231 MMG5_pTria pt;
1232 double v,v1;
1233 int ier;
1234 MMG5_int k,ip,ip1,ref,refint,refext;
1235 int8_t i,i1,i2,nmn,npl,nz;
1236
1237 for (k=1; k<=mesh->nt; k++) {
1238 pt = &mesh->tria[k];
1239 if ( !MG_EOK(pt) ) continue;
1240
1241 ref = pt->ref;
1242 nmn = npl = nz = 0;
1243 for (i=0; i<3; i++) {
1244 ip = pt->v[i];
1245 v = sol->m[ip];
1246
1247 if ( v > 0.0 )
1248 npl++;
1249 else if ( v < 0.0 )
1250 nmn++;
1251 else
1252 nz++;
1253 }
1254
1255 assert(nz < 3);
1256
1257 /* Keep the initial triangle references of the mesh if iso==2, set
1258 * positive and negative ls refs otherwise */
1259 if ( mesh->info.iso != 2 ) {
1260
1261 /* find if current reference should be splitted and the new positive and negative refs */
1262 ier = MMG5_isSplit(mesh,ref,&refint,&refext);
1263 if ( ier ) {
1264 if ( npl ) {
1265 assert( !nmn );
1266 pt->ref = refext;
1267 }
1268 else {
1269 assert ( nmn );
1270 pt->ref = refint;
1271 }
1272 }
1273 }
1274
1275 /* Set mesh->info.isoref ref at ls edges and at the points of these edges */
1276 if ( nz == 2 ) {
1277 for (i=0; i<3; i++) {
1278 ip = pt->v[MMG5_inxt2[i]];
1279 ip1 = pt->v[MMG5_iprv2[i]];
1280 v = sol->m[ip];
1281 v1 = sol->m[ip1];
1282 if ( v == 0.0 && v1 == 0.0) {
1283 pt->edg[i] = mesh->info.isoref;
1284 pt->tag[i] |= MG_REF;
1285 i1 = MMG5_inxt2[i];
1286 i2 = MMG5_inxt2[i1];
1287 mesh->point[pt->v[i1]].ref = mesh->info.isoref;
1288 mesh->point[pt->v[i2]].ref = mesh->info.isoref;
1289 }
1290 }
1291 }
1292
1293 }
1294
1295 return 1;
1296}
1297
1309int MMG5_chkmaniball(MMG5_pMesh mesh, MMG5_int start, int8_t istart) {
1310 MMG5_int refstart,*adja,k;
1311 int8_t i,i1;
1312
1313 k = start;
1314 i = istart;
1315
1316 i1 = MMG5_iprv2[i];
1317
1318
1319 MMG5_pTria pt = &mesh->tria[start];
1320 assert( MG_EDG(pt->tag[i1]) && (pt->edg[i1]==mesh->info.isoref) );
1321
1323 refstart = pt->ref;
1324 do {
1325 adja = &mesh->adja[3*(k-1)+1];
1326 i1 = MMG5_inxt2[i];
1327
1328 k = adja[i1] / 3;
1329 i = adja[i1] % 3;
1330
1331 if ( !k ) break;
1332
1333 if ( mesh->info.iso !=2 ) {
1335 if ( mesh->tria[k].ref != refstart) break;
1336 }
1337 else {
1340 if ( mesh->tria[k].edg[i]==mesh->info.isoref ) break;
1341 }
1342 i = MMG5_inxt2[i];
1343 }
1344 while ( k!=start );
1345
1346 assert(k!=start); //unexpected case
1347
1351 if ( k == 0 ) {
1352 k = start;
1353 i = istart;
1354
1355 adja = &mesh->adja[3*(k-1)+1];
1356 i1 = MMG5_iprv2[i];
1357 k = adja[i1] / 3;
1358 i = adja[i1] % 3;
1359 i = MMG5_iprv2[i];
1360
1362 if ( k == 0 ) return 1;
1363
1364 do {
1365 adja = &mesh->adja[3*(k-1)+1];
1366 i1 = MMG5_iprv2[i];
1367
1368 k = adja[i1] / 3;
1369 i = adja[i1] % 3;
1370
1371 if ( !k ) break;
1372
1373 if ( mesh->info.iso !=2 ) {
1374 /* Normal or multi-material mode: check for change in triangle references */
1375 if ( mesh->tria[k].ref == refstart) break;
1376 }
1377 else {
1378 /* Input reference preservation mode (mmgs --keep-ref option): Check if
1379 * we cross an isoref edge */
1380 if ( mesh->tria[k].edg[i]==mesh->info.isoref ) break;
1381 }
1382 i = MMG5_iprv2[i];
1383 }
1384 while ( k!=start );
1385
1386 assert(k!=start); //unexpected case
1387
1388 return !k;
1389 }
1390
1392 i = MMG5_inxt2[i];
1393 do {
1394 adja = &mesh->adja[3*(k-1)+1];
1395 i1 = MMG5_inxt2[i];
1396
1397 k = adja[i1] / 3;
1398 i = adja[i1] % 3;
1399
1400 if ( !k ) break;
1401
1402 if ( mesh->info.iso !=2 ) {
1403 /* Check tria ref change */
1404 if ( mesh->tria[k].ref == refstart) break;
1405 }
1406 else {
1407 /* Check if we cross an isoref edge */
1408 if ( mesh->tria[k].edg[i]==mesh->info.isoref ) break;
1409 }
1410
1411 i = MMG5_inxt2[i];
1412 }
1413 while ( k!=start );
1414
1416 if ( k != start )
1417 return 0;
1418
1419 return 1;
1420}
1421
1430 MMG5_pTria pt,pt1;
1431 MMG5_int *adja,k;
1432 MMG5_int cnt,iel;
1433 int8_t i,i1;
1434 static int8_t mmgWarn = 0;
1435
1437 for (k=1; k<=mesh->nt; k++) {
1438 pt = &mesh->tria[k];
1439 if ( !MG_EOK(pt) ) continue;
1440
1441 adja = &mesh->adja[3*(k-1)+1];
1442 cnt = 0;
1443 for (i=0; i<3; i++) {
1444 iel = adja[i] / 3;
1445
1446 if (!iel ) {
1447 cnt++;
1448 continue;
1449 }
1450 else {
1451 if ( mesh->info.iso !=2 ) {
1452 /* Multi-material mode may lead to have only 1 isoref edge around a
1453 point (due to nosplit option): check tria ref change */
1454 pt1 = &mesh->tria[iel];
1455 if ( pt1->ref != pt->ref ) cnt++;
1456 }
1457 else {
1458 /* keep-ref mode: check if isoref edge */
1459 if ( pt->edg[i] == mesh->info.isoref ) cnt++;
1460 }
1461 }
1462 }
1463 if( cnt == 3 ) {
1464 if ( !mmgWarn ) {
1465 mmgWarn = 1;
1466 fprintf(stderr,"\n ## Warning: %s: at least 1 triangle with 3 boundary"
1467 " edges.\n",__func__);
1468 }
1469 }
1470 }
1471
1475 for (k=1; k<=mesh->nt; k++) {
1476 pt = &mesh->tria[k];
1477 if ( !MG_EOK(pt) ) continue;
1478
1479 for (i=0; i<3; i++) {
1480 adja = &mesh->adja[3*(k-1)+1];
1481 iel = adja[i] / 3;
1482
1483 if (! iel ) continue;
1484
1485 if ( mesh->info.iso !=2 ) {
1486 /* Check change of tria ref */
1487 pt1 = &mesh->tria[iel];
1488 if ( pt->ref == pt1->ref || pt->edg[i]!= mesh->info.isoref ) continue;
1489 }
1490 else {
1491 /* Check isoref edge only */
1492 if ( pt->edg[i] != mesh->info.isoref ) continue;
1493 }
1494
1495 i1 = MMG5_inxt2[i];
1496 if ( !MMG5_chkmaniball(mesh,k,i1) ) {
1497 fprintf(stderr," *** Topological problem\n");
1498 fprintf(stderr," non manifold curve at point %" MMG5_PRId "\n",pt->v[i1]);
1499 fprintf(stderr," non manifold curve at tria %" MMG5_PRId " (ip %d)\n", MMG5_indElt(mesh,k),i1);
1500 return 0;
1501 }
1502 }
1503 }
1504
1505 if ( mesh->info.imprim > 0 || mesh->info.ddebug )
1506 fprintf(stdout," *** Manifold implicit surface.\n");
1507
1508 return 1;
1509}
int ier
tmp[*strlen0]
MMG5_pMesh MMG5_pSol * sol
MMG5_pMesh * mesh
MMG5_Info info
int MMG5_boulet(MMG5_pMesh mesh, MMG5_int start, int ip, MMG5_int *list, int8_t s, int8_t *opn)
Definition boulep.c:363
#define MMG5_EPS
#define MG_PLUS
Definition libmmgtypes.h:71
#define MG_MINUS
Definition libmmgtypes.h:76
static int MMG5_InvMat_code(int k, int attr)
Definition mmg2.c:58
static void MMG5_InvMat_error(MMG5_pInvMat pim, int ref, int k)
Definition mmg2.c:111
int MMG5_rmc(MMG5_pMesh mesh, MMG5_pSol sol)
Definition mmg2.c:917
static int MMG5_InvMat_check(MMG5_pInvMat pim, int key)
Definition mmg2.c:98
int MMG5_isLevelSet(MMG5_pMesh mesh, MMG5_int ref0, MMG5_int ref1)
Definition mmg2.c:477
int MMG5_isNotSplit(MMG5_pMesh mesh, MMG5_int ref)
Definition mmg2.c:453
int MMG5_ismaniball(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_int start, int8_t istart)
Definition mmg2.c:628
static int MMG5_isbr(MMG5_pMesh mesh, MMG5_int ref)
Definition mmg2.c:898
static int MMG5_InvMat_getParent(MMG5_pMesh mesh, MMG5_pInvMat pim, MMG5_int ref, MMG5_int *pref)
Definition mmg2.c:177
static MMG5_int MMG5_InvMat_key(MMG5_pInvMat pim, int ref)
Definition mmg2.c:46
static int MMG5_InvMat_getAttrib(MMG5_pInvMat pim, int ref)
Definition mmg2.c:84
int MMG5_snpval_ls(MMG5_pMesh mesh, MMG5_pSol sol)
Definition mmg2.c:508
int MMG5_isSplit(MMG5_pMesh mesh, MMG5_int ref, MMG5_int *refint, MMG5_int *refext)
Definition mmg2.c:417
static int MMG5_InvMat_set(MMG5_pMesh mesh, MMG5_pInvMat pim, int k)
Definition mmg2.c:129
static void MMG5_InvMat_print(MMG5_pMesh mesh, MMG5_pInvMat pim)
Definition mmg2.c:238
static double MMG5_voltri(MMG5_pMesh mesh, MMG5_int ip0, MMG5_int ip1, MMG5_int ip2)
Definition mmg2.c:753
int MMG5_MultiMat_init(MMG5_pMesh mesh)
Definition mmg2.c:326
int MMG5_getStartRef(MMG5_pMesh mesh, MMG5_int ref, MMG5_int *pref)
Definition mmg2.c:213
static double MMG5_vfrac(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_int k, int pm)
Definition mmg2.c:780
int MMG5_resetRef_ls(MMG5_pMesh mesh)
Definition mmg2.c:1194
int MMG5_chkmaniball(MMG5_pMesh mesh, MMG5_int start, int8_t istart)
Definition mmg2.c:1309
int MMG5_chkmanimesh(MMG5_pMesh mesh)
Definition mmg2.c:1429
static int MMG5_InvMat_getIndex(MMG5_pInvMat pim, int ref)
Definition mmg2.c:69
int MMG5_setref_ls(MMG5_pMesh mesh, MMG5_pSol sol)
Definition mmg2.c:1230
#define MMG5_SAFE_CALLOC(ptr, size, type, law)
#define MG_EOK(pt)
#define MMG5_ADD_MEM(mesh, size, message, law)
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
#define MMG5_TRIA_LMAX
static const uint8_t MMG5_inxt2[6]
#define MG_VOK(ppt)
#define MG_SMSGN(a, b)
#define MG_REF
#define MMG5_DEL_MEM(mesh, ptr)
MMG5_int ref
int8_t iso
int8_t ddebug
MMG5_int * br
double rmc
MMG5_pMat mat
MMG5_int isoref
MMG5_InvMat invmat
To store lookup table for references in the mesh (useful in LS mode)
MMG5_int offset
MMG5_int size
To store user-defined references in the mesh (useful in LS mode)
MMG5_int ref
int8_t dospl
MMG5_int rex
MMG5_int rin
MMG mesh structure.
MMG5_Info info
MMG5_int ne
MMG5_pPoint point
MMG5_int * adja
MMG5_int npmax
MMG5_int base
MMG5_pTetra tetra
MMG5_int nt
MMG5_pTria tria
MMG5_int np
MMG5_pEdge edge
MMG5_int na
Structure to store points of a MMG mesh.
double c[3]
MMG5_int ref
MMG5_int flag
MMG5_int ref
MMG5_int edg[3]
int16_t tag[3]
MMG5_int ref
MMG5_int flag
MMG5_int v[3]