Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
boulep_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"
37#include "libmmg3d_private.h"
38
39extern MMG5_Info info;
40
54int MMG5_boulevolp (MMG5_pMesh mesh, MMG5_int start, int ip, int64_t * list){
55 MMG5_pTetra pt,pt1;
56 MMG5_int base,*adja,nump,k,k1;
57 int ilist,cur;
58 int8_t j,l,i;
59
60 base = ++mesh->base;
61 pt = &mesh->tetra[start];
62 assert( 0<=ip && ip<4 && "unexpected local index for vertex");
63 nump = pt->v[ip];
64
65 /* Store initial tetrahedron */
66 pt->flag = base;
67 list[0] = 4*start + ip;
68 ilist=1;
69
70 /* Explore list and travel by adjacency through elements sharing p */
71 cur = 0;
72 while ( cur < ilist ) {
73 k = list[cur] / 4;
74 i = list[cur] % 4; // index of point p in tetra k
75 adja = &mesh->adja[4*(k-1)+1];
76
77 for (l=0; l<3; l++) {
78 i = MMG5_inxt3[i];
79 k1 = adja[i];
80 if ( !k1 ) continue;
81 k1 /= 4;
82 pt1 = &mesh->tetra[k1];
83 if ( pt1->flag == base ) continue;
84 pt1->flag = base;
85 for (j=0; j<4; j++)
86 if ( pt1->v[j] == nump ) break;
87 assert(j<4);
88 /* overflow */
89 if ( ilist > MMG3D_LMAX-3 ) return 0;
90 list[ilist] = 4*k1+j;
91 ilist++;
92 }
93 cur++;
94 }
95 return ilist;
96}
97
113int MMG3D_findEdge(MMG5_pMesh mesh,MMG5_pTetra pt,MMG5_int k,MMG5_int na,MMG5_int nb,int error,
114 int8_t *mmgWarn,int8_t *ia) {
115 int8_t ipa,ipb;
116
117 /* identification of edge number in tetra k */
118 for ((*ia)=0; (*ia)<6; (*ia)++) {
119 ipa = MMG5_iare[(*ia)][0];
120 ipb = MMG5_iare[(*ia)][1];
121 if ( (pt->v[ipa] == na && pt->v[ipb] == nb) ||
122 (pt->v[ipa] == nb && pt->v[ipb] == na)) break;
123 }
124
125 /* fail if the edge na-nb is not found */
126 if ( (*ia)<6 ) return 1;
127
128 if ( error ) {
129 fprintf(stderr,"\n ## Error: %s: wrong edge's shell: "
130 " edge %" MMG5_PRId " %" MMG5_PRId " not found in tetra %" MMG5_PRId ".\n",__func__,
131 MMG3D_indPt(mesh,na),
133 fprintf(stderr," Exit program.\n");
134 }
135 else {
136 if ( !(*mmgWarn) ) {
137 (*mmgWarn) = 1;
138 fprintf(stderr,"\n ## Warning: %s: at least one wrong edge's"
139 " shell.\n",__func__);
140 }
141 }
142 return 0;
143}
144
145static inline
146void MMG3D_compute_tangent(MMG5_pMesh mesh,int nump,int ip0,int ip1,double t[3]) {
147 MMG5_pPoint ppt,p0,p1;
148 double l0,l1,dd;
149 int8_t i;
150
151 ppt = &mesh->point[nump];
152 p0 = &mesh->point[ip0];
153 p1 = &mesh->point[ip1];
154
155 l0 = (ppt->c[0] - p0->c[0])*(ppt->c[0] - p0->c[0]) \
156 + (ppt->c[1] - p0->c[1])*(ppt->c[1] - p0->c[1]) + (ppt->c[2] - p0->c[2])*(ppt->c[2] - p0->c[2]);
157 l1 = (ppt->c[0] - p1->c[0])*(ppt->c[0] - p1->c[0]) \
158 + (ppt->c[1] - p1->c[1])*(ppt->c[1] - p1->c[1]) + (ppt->c[2] - p1->c[2])*(ppt->c[2] - p1->c[2]);
159 l0 = sqrt(l0);
160 l1 = sqrt(l1);
161
162 if ( (l0 < MMG5_EPSD2) || (l1 < MMG5_EPSD2) ) {
163 for ( i=0; i<3; ++i ) {
164 t[i] = p1->c[i] - p0->c[i];
165 }
166 }
167 else if ( l0 < l1 ) {
168 dd = l0 / l1;
169 for ( i=0; i<3; ++i ) {
170 t[i] = dd*(p1->c[i] - ppt->c[i]) + ppt->c[i] - p0->c[i];
171 }
172 }
173 else {
174 dd = l1 / l0;
175 for ( i=0; i<3; ++i ) {
176 t[i] = dd*(p0->c[i] - ppt->c[i]) + ppt->c[i] - p1->c[i];
177 }
178 }
179
180 return;
181}
182
196int MMG5_boulenm(MMG5_pMesh mesh,MMG5_int start,int ip,int iface,
197 double n[3],double t[3]) {
198 MMG5_pTetra pt;
199 double dd,nt[3];
200 int nr,nnm;
201 MMG5_int base,nump,k,*adja,piv,nvstart,aux,na,nb,adj,fstart,ip0,ip1;
202 int16_t tag;
203 int8_t iopp,ipiv,indb,inda,i,isface;
204 int8_t indedg[4][4] = { {-1,0,1,2}, {0,-1,3,4}, {1,3,-1,5}, {2,4,5,-1} };
205
206 base = ++mesh->base;
207 nr = nnm = 0;
208 ip0 = ip1 = 0;
209
210 memset(n,0x00,3*sizeof(double));
211 memset(t,0x00,3*sizeof(double));
212
213 pt = &mesh->tetra[start];
214 nump = pt->v[ip];
215 k = start;
216
217 na = pt->v[ip];
218 nb = pt->v[MMG5_idir[iface][MMG5_inxt2[MMG5_idirinv[iface][ip]]]];
219 piv = pt->v[MMG5_idir[iface][MMG5_iprv2[MMG5_idirinv[iface][ip]]]];
220
221 iopp = iface;
222 fstart = 4*k+iopp;
223 do {
224 /* computation of normal and tangent at nump */
225 if ( MMG5_norface(mesh,k,iopp,nt) ) {
226 n[0] += nt[0];
227 n[1] += nt[1];
228 n[2] += nt[2];
229 }
230
231 if ( pt->xt ) {
232 for ( inda=0; inda<4; inda++ ){
233 if ( pt->v[inda]==na ) break;
234 }
235 for ( indb=0; indb<4; indb++ ){
236 if ( pt->v[indb]==nb ) break;
237 }
238 assert( (inda < 4) && (indb < 4));
239 tag = mesh->xtetra[pt->xt].tag[indedg[inda][indb]];
240 }
241
242 else tag = 0;
243
244 if ( MG_EDG(tag) && !(tag & MG_NOM) )
245 nr++;
246 else if ( tag & MG_NOM ) {
247 nnm++;
248 if ( !ip0 )
249 ip0 = nb;
250 else
251 ip1 = nb;
252 }
253
254 /* A boundary face has been hit : change travel edge */
255 aux = nb;
256 nb = piv;
257 piv = aux;
258 nvstart = k;
259 adj = k;
260
261 /* Now unfold shell of edge (na,nb) starting from k (included) */
262 do {
263 k = adj;
264 pt = &mesh->tetra[k];
265 adja = &mesh->adja[4*(k-1)+1];
266 if ( pt->flag != base ) {
267 for (i=0; i<4; i++)
268 if ( pt->v[i] == nump ) break;
269 assert(i<4);
270 pt->flag = base;
271 }
272
273 /* identification of edge number in tetra k */
274 if ( !MMG3D_findEdge(mesh,pt,k,na,nb,1,NULL,&i) ) return -1;
275
276 /* set sense of travel */
277 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
278 adj = adja[ MMG5_ifar[i][0] ] / 4;
279 ipiv = MMG5_ifar[i][1];
280 iopp = MMG5_ifar[i][0];
281 piv = pt->v[ipiv];
282 }
283 else {
284 adj = adja[ MMG5_ifar[i][1] ] / 4;
285 ipiv = MMG5_ifar[i][0];
286 iopp = MMG5_ifar[i][1];
287 piv = pt->v[ipiv];
288 }
289 isface = (adja[iopp] == 0);
290 }
291 while ( adj && (adj != nvstart) && !isface );
292 }
293 while ( 4*k+iopp != fstart );
294
295 if ( (nr > 0 && nnm > 0) || nnm != 2 ) {
296 /* We pass here for non-manifold meshes with only edge connection */
297 return 0;
298 }
299
300 dd = n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
301 if ( dd > MMG5_EPSD2 ) {
302 dd = 1.0 / sqrt(dd);
303 n[0] *= dd;
304 n[1] *= dd;
305 n[2] *= dd;
306 }
307 assert( ip0 && ip1 );
308 if ( ip0 == ip1 ) return 0;
309
310 MMG3D_compute_tangent(mesh,nump,ip0,ip1,t);
311
312 dd = t[0]*n[0] + t[1]*n[1] + t[2]*n[2];
313 t[0] -= dd*n[0];
314 t[1] -= dd*n[1];
315 t[2] -= dd*n[2];
316
317 dd = t[0]*t[0] + t[1]*t[1] + t[2]*t[2];
318 if ( dd > MMG5_EPSD2 ) {
319 dd = 1.0 / sqrt(dd);
320 t[0] *= dd;
321 t[1] *= dd;
322 t[2] *= dd;
323 }
324
325 return 1;
326}
327
342int MMG5_boulenmInt(MMG5_pMesh mesh,MMG5_int start,int ip,double t[3]) {
343 MMG5_pTetra pt,pt1;
344 MMG5_pxTetra pxt;
345 double dd;
346 MMG5_int base,k,kk,ip0,ip1,nump,na,nb,list[MMG3D_LMAX+2],*adja;
347 int cur,ilist;
348 int8_t i,j,ii,ie;
349
350 base = ++mesh->base;
351 ip0 = ip1 = 0;
352 cur = ilist = 0;
353
354 /* Store initial tetrahedron */
355 pt = &mesh->tetra[start];
356 nump = pt->v[ip];
357 list[0] = 4*start+ip;
358 pt->flag = base;
359 ilist++;
360
361 while ( cur < ilist ) {
362 k = list[cur] / 4;
363 i = list[cur] % 4;
364 pt = &mesh->tetra[k];
365
366 /* If pt bears geometric information, search for endpoints of the NOM curve of ppt */
367 if ( pt->xt ) {
368 pxt = &mesh->xtetra[pt->xt];
369 for (j=0; j<3; j++) {
370 ie = MMG5_arpt[i][j];
371 if ( pxt->tag[ie] & MG_NOM ) {
372 na = pt->v[MMG5_iare[ie][0]];
373 nb = pt->v[MMG5_iare[ie][1]];
374 /* Store nb, if need be */
375 if ( na == nump ) {
376 if ( ip0 == 0 ) ip0 = nb;
377 else if ( ip1 == 0 ) {
378 if ( ip0 != nb ) ip1 = nb;
379 }
380 else {
381 if ( ip0 != nb && ip1 != nb ) return 0;
382 }
383 }
384 /* Store na, if need be */
385 else {
386 if ( ip0 == 0 ) ip0 = na;
387 else if ( ip1 == 0 ) {
388 if ( ip0 != na ) ip1 = na;
389 }
390 else {
391 if ( ip0 != na && ip1 != na ) return 0;
392 }
393 }
394 }
395 }
396 }
397
398 /* Pile up tetrahedra in the ball of nump */
399 adja = &mesh->adja[4*(k-1)+1];
400
401 for (j=0; j<3; j++) {
402 i = MMG5_inxt3[i];
403 kk = adja[i] / 4;
404 assert ( kk && "point is not an internal nm-point");
405
406 if ( !kk ) {
407 /* point is not an internal non manifold point */
408 return 0;
409 }
410
411 pt1 = &mesh->tetra[kk];
412 if ( pt1->flag == base ) continue;
413
414 for (ii=0; ii<4; ii++)
415 if ( pt1->v[ii] == nump ) break;
416 assert ( ii < 4 );
417
418 list[ilist] = 4*kk+ii;
419 pt1->flag = base;
420 if ( ilist > MMG3D_LMAX-3 ) return 0;
421 ilist++;
422 }
423
424 cur++;
425 }
426
427 /* At this point, the two points connected to ppt via the NOM curve are ip0 and ip1 */
428 MMG3D_compute_tangent(mesh,nump,ip0,ip1,t);
429
430 dd = t[0]*t[0] + t[1]*t[1] + t[2]*t[2];
431 if ( dd > MMG5_EPSD2 ) {
432 dd = 1.0 / sqrt(dd);
433 t[0] *= dd;
434 t[1] *= dd;
435 t[2] *= dd;
436 }
437
438 return 1;
439}
440
455int MMG5_boulernm(MMG5_pMesh mesh,MMG5_Hash *hash,MMG5_int start,int ip,MMG5_int *ng,MMG5_int *nr,MMG5_int *nm){
456 MMG5_pTetra pt,pt1;
457 MMG5_pxTetra pxt;
458 MMG5_hedge *ph;
459 MMG5_int *adja,nump,k,k1;
460 int ns,ilist,cur;
461 MMG5_int list[MMG3D_LMAX+2],base,ia,ib,a,b,key,jj;
462 int8_t j,l,i;
463 uint8_t ie;
464
465 /* reset the hash table */
466 for ( k=0; k<=hash->max; ++k ) {
467 hash->item[k].a = 0;
468 hash->item[k].b = 0;
469 }
470
471 for ( k=0; k<=hash->siz; ++k ) {
472 hash->item[k].nxt = 0;
473 }
474 for (k=hash->siz; k<hash->max; k++) {
475 hash->item[k].nxt = k+1;
476 }
477
478 base = ++mesh->base;
479 pt = &mesh->tetra[start];
480 nump = pt->v[ip];
481
482 /* Store initial tetrahedron */
483 pt->flag = base;
484 list[0] = 4*start + ip;
485 ilist = 1;
486
487 *ng = *nr = *nm = ns = 0;
488
489 /* Explore list and travel by adjacency through elements sharing p */
490 cur = 0;
491 while ( cur < ilist ) {
492 k = list[cur] / 4;
493 i = list[cur] % 4; // index of point p in tetra k
494 pt = &mesh->tetra[k];
495
496 /* Count the number of ridge of ref edges passing through ip. */
497 if ( pt->xt ) {
498 pxt = &mesh->xtetra[pt->xt];
499 for (l=0; l<3; ++l) {
500 ie = MMG5_arpt[i][l];
501
502 if ( MG_EDG(pxt->tag[ie]) || (MG_NOM & pxt->tag[ie]) ) {
503 /* Seek if we have already seen the edge. If not, hash it and
504 * increment ng or nr.*/
505 a = pt->v[MMG5_iare[ie][0]];
506 b = pt->v[MMG5_iare[ie][1]];
507 ia = MG_MIN(a,b);
508 ib = MG_MAX(a,b);
509 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
510 ph = &hash->item[key];
511
512 if ( ph->a == ia && ph->b == ib )
513 continue;
514 else if ( ph->a ) {
515 while ( ph->nxt && ph->nxt < hash->max ) {
516 ph = &hash->item[ph->nxt];
517 if ( ph->a == ia && ph->b == ib ) continue;
518 }
519 ph->nxt = hash->nxt;
520 ph = &hash->item[hash->nxt];
521
522 if ( hash->nxt >= hash->max-1 ) {
523 if ( mesh->info.ddebug )
524 fprintf(stderr,"\n ## Warning: %s: memory alloc problem (edge):"
525 " %" MMG5_PRId "\n",__func__,hash->max);
527 "MMG5_edge",return -1);
528 /* ph pointer may be false after realloc */
529 ph = &hash->item[hash->nxt];
530
531 for (jj=ph->nxt; jj<hash->max; jj++) hash->item[jj].nxt = jj+1;
532 }
533 hash->nxt = ph->nxt;
534 }
535
536 /* insert new edge */
537 ph->a = ia;
538 ph->b = ib;
539 ph->nxt = 0;
540
541 /* Order of following tests impacts the ridge and non-manifold edges
542 * count (an edge that has both tags pass only in first test) but
543 * should not influence the setting for corners and required tags in
544 * setVertexNmTag function) */
545 if ( pxt->tag[ie] & MG_GEO ) {
546 ++(*ng);
547 }
548 else if ( pxt->tag[ie] & MG_NOM ) {
549 ++(*nm);
550 }
551 else if ( pxt->tag[ie] & MG_REF ) {
552 ++(*nr);
553 }
554 ++ns;
555 }
556 }
557 }
558
559 /* Continue to travel */
560 adja = &mesh->adja[4*(k-1)+1];
561
562 for (l=0; l<3; l++) {
563 i = MMG5_inxt3[i];
564 k1 = adja[i];
565 if ( !k1 ) continue;
566 k1 /= 4;
567 pt1 = &mesh->tetra[k1];
568 if ( pt1->flag == base ) continue;
569 pt1->flag = base;
570 for (j=0; j<4; j++)
571 if ( pt1->v[j] == nump ) break;
572 assert(j<4);
573 /* overflow */
574 if ( ilist > MMG3D_LMAX-3 ) return 0;
575 list[ilist] = 4*k1+j;
576 ilist++;
577 }
578 cur++;
579 }
580
581 return ns;
582}
583
607int MMG5_boulesurfvolp(MMG5_pMesh mesh,MMG5_int start,int ip,int iface,
608 int64_t *listv,int *ilistv,MMG5_int *lists,int*ilists, int isnm)
609{
610 MMG5_pTetra pt,pt1;
611 MMG5_pxTetra pxt;
612 MMG5_int k,*adja,nump,k1,fstart,piv,na,nb,adj,nvstart,aux,cur,base;
613 int8_t iopp,ipiv,i,j,l,isface;
614 static int8_t mmgErr0=0, mmgErr1=0, mmgErr2=0;
615
616 if ( isnm ) assert(!mesh->adja[4*(start-1)+iface+1]);
617
618 base = ++mesh->base;
619 *ilists = 0;
620 *ilistv = 0;
621
622 pt = &mesh->tetra[start];
623 nump = pt->v[ip];
624 k = start;
625
626 na = pt->v[ip];
627 nb = pt->v[MMG5_idir[iface][MMG5_inxt2[MMG5_idirinv[iface][ip]]]];
628 piv = pt->v[MMG5_idir[iface][MMG5_iprv2[MMG5_idirinv[iface][ip]]]];
629
630 iopp = iface;
631 fstart = 4*k+iopp;
632
633 do {
634 /* A boundary face has been hit : change travel edge */
635 lists[(*ilists)] = 4*k+iopp;
636 (*ilists)++;
637
638 assert ( mesh->tetra[k].xt && "tetra of surfacic ball has a xtetra (bdy face) ");
639
640 if ( *ilists >= MMG3D_LMAX ) {
641 if ( !mmgErr0 ) {
642 fprintf(stderr,"\n ## Warning: %s: problem in surface remesh process."
643 " Surface ball of at least 1 point (%" MMG5_PRId ") contains too"
644 " many elts.\n"
645 " ## Try to modify the hausdorff number "
646 " or/and the maximum edge size.\n",__func__,
647 MMG3D_indPt(mesh,nump));
648 mmgErr0 = 1;
649 }
650
651 return -1;
652 }
653
654 aux = nb;
655 nb = piv;
656 piv = aux;
657 nvstart = k;
658 adj = k;
659
660 /* Now unfold shell of edge (na,nb) starting from k (included)*/
661 do {
662 k = adj;
663 pt = &mesh->tetra[k];
664 adja = &mesh->adja[4*(k-1)+1];
665 if ( pt->flag != base ) {
666 for (i=0; i<4; i++)
667 if ( pt->v[i] == nump ) break;
668 assert(i<4);
669 listv[(*ilistv)] = 4*k+i;
670 (*ilistv)++;
671 pt->flag = base;
672 }
673
674 /* identification of edge number in tetra k */
675 if ( !MMG3D_findEdge(mesh,pt,k,na,nb,0,&mmgErr2,&i) ) return -1;
676
677 /* set sense of travel */
678 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
679 iopp = MMG5_ifar[i][0];
680 ipiv = MMG5_ifar[i][1];
681 adj = adja[ iopp ] / 4;
682 piv = pt->v[ipiv];
683 }
684 else {
685 ipiv = MMG5_ifar[i][0];
686 iopp = MMG5_ifar[i][1];
687 adj = adja[ iopp ] / 4;
688 piv = pt->v[ipiv];
689 }
690 if ( isnm ) {
691 isface = (adja[iopp] == 0);
692 }
693 else {
694 isface = 0;
695 if(pt->xt){
696 pxt = &mesh->xtetra[pt->xt];
697 isface = (MG_BDY & pxt->ftag[iopp]);
698 }
699 }
700 }
701 while ( adj && (adj != nvstart) && !isface );
702 }
703 while ( 4*k+iopp != fstart );
704
705 /* Now, surfacic ball is complete ; finish travel of volumic ball */
706 cur = 0; // Check numerotation
707 while ( cur < (*ilistv) ) {
708 k = listv[cur]/4;
709 i = listv[cur]%4; // index of point p in tetra k
710 adja = &mesh->adja[4*(k-1)+1];
711
712 for (l=0; l<3; l++) {
713 i = MMG5_inxt3[i];
714 k1 = adja[i];
715 if ( !k1 ) continue;
716 k1/=4;
717 pt1 = &mesh->tetra[k1];
718 if ( pt1->flag == base ) continue;
719 pt1->flag = base;
720
721 for (j=0; j<4; j++)
722 if ( pt1->v[j] == nump ) break;
723 assert(j<4);
724
725 /* overflow */
726 if ( *ilistv > MMG3D_LMAX-3 ) {
727 if ( !mmgErr1 ) {
728 fprintf(stderr,"\n ## Warning: %s: problem in remesh process."
729 " Volumic ball of point %" MMG5_PRId " contains too many elts.\n",
730 __func__,MMG3D_indPt(mesh,nump));
731 fprintf(stderr,"\n ## Try to modify the hausdorff number,"
732 " or/and the maximum mesh.\n");
733 mmgErr1 = 1;
734 }
735 return -1;
736 }
737 listv[(*ilistv)] = 4*k1+j;
738 (*ilistv)++;
739 }
740 cur++;
741 }
742
743 return 1;
744}
745
771int MMG5_boulesurfvolpNom(MMG5_pMesh mesh,MMG5_int start,int ip,int iface,
772 int64_t *listv,int *ilistv,MMG5_int *lists,int *ilists,
773 MMG5_int *refmin,MMG5_int *refplus,int isnm)
774{
775 MMG5_pTetra pt,pt1;
776 MMG5_pxTetra pxt;
777 MMG5_int k,k1,nump,*adja,piv,na,nb,adj,cur,nvstart,fstart,aux,base;
778 int8_t iopp,ipiv,i,j,l,isface;
779 static int8_t mmgErr0=0, mmgErr1=0, mmgErr2=0;
780
781 if ( isnm ) assert(!mesh->adja[4*(start-1)+iface+1]);
782
783 base = ++mesh->base;
784 *ilists = 0;
785 *ilistv = 0;
786 *refmin = -1;
787 *refplus = -1;
788
789 pt = &mesh->tetra[start];
790 nump = pt->v[ip];
791 k = start;
792
793 na = pt->v[ip];
794 nb = pt->v[MMG5_idir[iface][MMG5_inxt2[MMG5_idirinv[iface][ip]]]];
795 piv = pt->v[MMG5_idir[iface][MMG5_iprv2[MMG5_idirinv[iface][ip]]]];
796
797 iopp = iface;
798 fstart = 4*k+iopp;
799
800 do {
801 /* A boundary face has been hit : change travel edge */
802 lists[(*ilists)] = 4*k+iopp;
803 (*ilists)++;
804 if ( *ilists >= MMG3D_LMAX ) {
805 if ( !mmgErr0 ) {
806 fprintf(stderr,"\n ## Warning: %s: problem in surface remesh process."
807 " Surface ball of at least 1 point (%" MMG5_PRId ") contains too"
808 " many elts.\n"
809 " ## Try to modify the hausdorff number "
810 " or/and the maximum edge size.\n",__func__,
811 MMG3D_indPt(mesh,nump));
812 mmgErr0 = 1;
813 }
814
815 return -1;
816 }
817
818 aux = nb;
819 nb = piv;
820 piv = aux;
821 nvstart = k;
822 adj = k;
823
824 /* Now unfold shell of edge (na,nb) starting from k (included)*/
825 do {
826 k = adj;
827 pt = &mesh->tetra[k];
828 adja = &mesh->adja[4*(k-1)+1];
829 if ( pt->flag != base ) {
830 for (i=0; i<4; i++)
831 if ( pt->v[i] == nump ) break;
832 assert(i<4);
833 listv[(*ilistv)] = 4*k+i;
834 (*ilistv)++;
835
836 /* Identify references of both subdomains in presence */
837 if ( *refmin == -1 )
838 *refmin = pt->ref;
839 else {
840 if ( *refplus == -1 ) {
841 if ( pt->ref != *refmin ) *refplus = pt->ref;
842 }
843 else if ( pt->ref != *refmin && pt->ref != *refplus ) return -1;
844 }
845 pt->flag = base;
846 }
847
848 /* identification of edge number in tetra k */
849 if ( !MMG3D_findEdge(mesh,pt,k,na,nb,0,&mmgErr2,&i) ) return -1;
850
851 /* set sense of travel */
852 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
853 iopp = MMG5_ifar[i][0];
854 ipiv = MMG5_ifar[i][1];
855 adj = adja[ iopp ] / 4;
856 piv = pt->v[ipiv];
857 }
858 else {
859 ipiv = MMG5_ifar[i][0];
860 iopp = MMG5_ifar[i][1];
861 adj = adja[ iopp ] / 4;
862 piv = pt->v[ipiv];
863 }
864 if ( isnm ) {
865 isface = (adja[iopp] == 0);
866 }
867 else {
868 isface = 0;
869 if(pt->xt){
870 pxt = &mesh->xtetra[pt->xt];
871 isface = (MG_BDY & pxt->ftag[iopp]);
872 }
873 }
874 }
875 while ( adj && (adj != nvstart) && !isface );
876 }
877 while ( 4*k+iopp != fstart );
878
879 /* Now, surfacic ball is complete ; finish travel of volumic ball */
880 cur = 0; // Check numerotation
881 while ( cur < (*ilistv) ) {
882 k = listv[cur]/4;
883 i = listv[cur]%4; // index of point p in tetra k
884 adja = &mesh->adja[4*(k-1)+1];
885
886 for (l=0; l<3; l++) {
887 i = MMG5_inxt3[i];
888 k1 = adja[i];
889 if ( !k1 ) continue;
890 k1/=4;
891 pt1 = &mesh->tetra[k1];
892 if ( pt1->flag == base ) continue;
893 pt1->flag = base;
894
895 for (j=0; j<4; j++)
896 if ( pt1->v[j] == nump ) break;
897 assert(j<4);
898
899 /* overflow */
900 if ( *ilistv > MMG3D_LMAX-3 ) {
901 if ( !mmgErr1 ) {
902 fprintf(stderr,"\n ## Warning: %s: problem in remesh process."
903 " Volumic ball of point %" MMG5_PRId " contains too many elts.\n",
904 __func__,MMG3D_indPt(mesh,nump));
905 fprintf(stderr,"\n ## Try to modify the hausdorff number,"
906 " or/and the maximum mesh.\n");
907 mmgErr1 = 1;
908 }
909 return -1;
910 }
911 listv[(*ilistv)] = 4*k1+j;
912 (*ilistv)++;
913
914 /* Identify references of both subdomains in presence */
915 if ( *refmin == -1 )
916 *refmin = pt1->ref;
917 else {
918 if ( *refplus == -1 ) {
919 if ( pt1->ref != *refmin ) *refplus = pt1->ref;
920 }
921 else if ( pt1->ref != *refmin && pt1->ref != *refplus ) return -1;
922 }
923 }
924 cur++;
925 }
926
927 return 1;
928}
929
930
952int MMG5_bouletrid(MMG5_pMesh mesh,MMG5_int start,int iface,int ip,int *il1,MMG5_int *l1,
953 int *il2,MMG5_int *l2,MMG5_int *ip0,MMG5_int *ip1)
954{
955 MMG5_pTetra pt;
956 MMG5_pxTetra pxt;
957 MMG5_pPoint ppt;
958 MMG5_int k,*adja,*list1,*list2,aux;
959 MMG5_int na, nb, piv,lists[MMG3D_LMAX+2], base;
960 MMG5_int idp, fstart, nvstart, adj;
961 int ilists, iopp, ipiv,*ilist1,*ilist2;
962 int ifac,idx,idx2,idx_tmp,i1,isface;
963 double *n1,*n2,nt[3],ps1,ps2;
964 int8_t i;
965 static int8_t mmgErr0=0,mmgErr1=0;
966
967 pt = &mesh->tetra[start];
968 if ( !MG_EOK(pt) ) return 0;
969
970#ifndef NDEBUG
971 assert(pt->xt);
972 pxt = &mesh->xtetra[pt->xt];
973 // We must call this function on a well orientated boundary face (to build the
974 // direct surfacic ball).
975 assert(pxt->ftag[iface] & MG_BDY);
976 assert( MG_GET(pxt->ori,iface) );
977#endif
978
979 idp = pt->v[ip];
980 k = start;
981
982 ppt = &mesh->point[idp];
983 assert( ppt->tag & MG_GEO );
984
985 na = pt->v[ip];
986 nb = pt->v[MMG5_idir[iface][MMG5_inxt2[MMG5_idirinv[iface][ip]]]];
987 piv = pt->v[MMG5_idir[iface][MMG5_iprv2[MMG5_idirinv[iface][ip]]]];
988
989 iopp = iface;
990 fstart = 4*k+iopp;
991
992 base = ++mesh->base;
993
994 /* Set pointers on lists il1 and il2 to have il1 associated to the normal of
995 the face iface.*/
996 MMG5_norpts(mesh, pt->v[MMG5_idir[iface][0]],pt->v[MMG5_idir[iface][1]],
997 pt->v[MMG5_idir[iface][2]],nt);
998
999 n1 = &(mesh->xpoint[ppt->xp].n1[0]);
1000 n2 = &(mesh->xpoint[ppt->xp].n2[0]);
1001 ps1 = n1[0]*nt[0] + n1[1]*nt[1] + n1[2]*nt[2];
1002 ps2 = n2[0]*nt[0] + n2[1]*nt[1] + n2[2]*nt[2];
1003
1004 if ( fabs(ps1) < fabs(ps2) ) {
1005 list1 = l2;
1006 list2 = l1;
1007 ilist1 = il2;
1008 ilist2 = il1;
1009 }
1010 else {
1011 list1 = l1;
1012 list2 = l2;
1013 ilist1 = il1;
1014 ilist2 = il2;
1015 }
1016 *ilist1 = 0;
1017 *ilist2 = 0;
1018
1019 /* First: fill the surfacic ball. */
1020 ilists = 0;
1021 do {
1022 /* A boundary face has been hit : change travel edge */
1023 lists[ilists] = 4*k+iopp;
1024 ilists++;
1025 if ( ilists >= MMG3D_LMAX ) {
1026 if ( !mmgErr0 ) {
1027 fprintf(stderr,"\n ## Warning: %s: problem in remesh process."
1028 " Volumic ball of point %" MMG5_PRId " contains too many elts.\n",
1029 __func__,MMG3D_indPt(mesh,idp));
1030 fprintf(stderr,"\n ## Try to modify the hausdorff number,"
1031 " or/and the maximum mesh.\n");
1032 mmgErr0 = 1;
1033 }
1034 return 0;
1035 }
1036
1037 aux = nb;
1038 nb = piv;
1039 piv = aux;
1040 nvstart = k;
1041 adj = k;
1042
1043 /* Now unfold shell of edge (na,nb) starting from k (included) */
1044 do {
1045 k = adj;
1046 pt = &mesh->tetra[k];
1047 adja = &mesh->adja[4*(k-1)+1];
1048 pt->flag = base;
1049
1050 /* identification of edge number in tetra k */
1051 if ( !MMG3D_findEdge(mesh,pt,k,na,nb,0,&mmgErr1,&i) ) return -1;
1052
1053 /* set sense of travel */
1054 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
1055 iopp = MMG5_ifar[i][0];
1056 ipiv = MMG5_ifar[i][1];
1057 adj = adja[ iopp ] / 4;
1058 piv = pt->v[ipiv];
1059 }
1060 else {
1061 ipiv = MMG5_ifar[i][0];
1062 iopp = MMG5_ifar[i][1];
1063 adj = adja[ iopp ] / 4;
1064 piv = pt->v[ipiv];
1065 }
1066 isface = 0;
1067 if(pt->xt){
1068 pxt = &mesh->xtetra[pt->xt];
1069 isface = (MG_BDY & pxt->ftag[iopp]);
1070 }
1071 }
1072 while ( adj && (adj != nvstart) && !isface );
1073 }
1074 // Remark: here the test k!=start is a security bound: theorically it is
1075 // useless but in case of bad edge tag, it ensure that the loop is not
1076 // infinite.
1077 while ( 4*k+iopp != fstart );
1078
1079 /* Second: travel through the surface ball until meeting a ridge. */
1080 for (idx=0; idx!=ilists; ++idx) {
1081 k = lists[idx]/4;
1082 ifac = lists[idx]%4;
1083 pt = &mesh->tetra[k];
1084 assert(pt->xt);
1085 pxt = &mesh->xtetra[pt->xt];
1086
1087 for ( i=0; i<3; ++i ) {
1088 if ( pt->v[MMG5_idir[ifac][i]] == idp ) break;
1089 }
1090 assert(i<3);
1091
1092 i1 = MMG5_inxt2[i];
1093 if ( pxt->tag[MMG5_iarf[ifac][i1]] & MG_GEO ) break;
1094 }
1095 assert(idx < ilists);
1096 *ip0 = pt->v[MMG5_idir[ifac][MMG5_iprv2[i]]];
1097
1098 /* Start from the hit boundary, until another boundary is hit and complete the
1099 * second ball */
1100 idx = (idx+1)%ilists;
1101 for (idx2=idx; idx2!=ilists+idx; ++idx2) {
1102 idx_tmp = idx2%ilists;
1103 k = lists[idx_tmp]/4;
1104 ifac = lists[idx_tmp]%4;
1105 pt = &mesh->tetra[k];
1106 assert(pt->xt);
1107 pxt = &mesh->xtetra[pt->xt];
1108
1109 if ( (*ilist2) > MMG3D_LMAX-2 ) return 0;
1110 list2[(*ilist2)] = 4*k+ifac;
1111 (*ilist2)++;
1112
1113 for ( i=0; i<3; ++i ) {
1114 if ( pt->v[MMG5_idir[ifac][i]] == idp ) break;
1115 }
1116 assert(i<3);
1117
1118 i1 = MMG5_inxt2[i];
1119 if ( pxt->tag[MMG5_iarf[ifac][i1]] & MG_GEO ) break;
1120 }
1121 assert(idx2 != ilists+idx);
1122 *ip1 = pt->v[MMG5_idir[ifac][MMG5_iprv2[i]]];
1123
1124 /* Start again from the newly hit boundary, until another boundary is hit and
1125 * complete the first ball */
1126 idx = (idx2+1)%ilists;
1127 for (idx2=idx; idx2 != idx+ilists; ++idx2) {
1128 idx_tmp = idx2%ilists;
1129 k = lists[idx_tmp]/4;
1130 ifac = lists[idx_tmp]%4;
1131 pt = &mesh->tetra[k];
1132 assert(pt->xt);
1133 pxt = &mesh->xtetra[pt->xt];
1134
1135 if ( (*ilist1) > MMG3D_LMAX-2 ) return 0;
1136 list1[(*ilist1)] = 4*k+ifac;
1137 (*ilist1)++;
1138
1139 for ( i=0; i<3; ++i ) {
1140 if ( pt->v[MMG5_idir[ifac][i]] == idp ) break;
1141 }
1142 assert(i<3);
1143
1144 i1 = MMG5_inxt2[i];
1145 if ( pxt->tag[MMG5_iarf[ifac][i1]] & MG_GEO ) break;
1146 }
1147 assert(idx2 != ilists+idx);
1148 assert(*ip0 == pt->v[MMG5_idir[ifac][MMG5_iprv2[i]]]);
1149
1150 return 1;
1151}
1152
1169static inline
1170int MMG3D_settag_oneDir(MMG5_pMesh mesh,MMG5_int start, MMG5_int na, MMG5_int nb,
1171 int16_t tag,int edg, MMG5_int piv,MMG5_int adj) {
1172 MMG5_pTetra pt;
1173 MMG5_pxTetra pxt;
1174 MMG5_int *adja;
1175 int16_t taginit;
1176 int8_t i;
1177
1178 while ( adj && (adj != start) ) {
1179 pt = &mesh->tetra[adj];
1180
1181 /* identification of edge number in tetra adj */
1182 if ( !MMG3D_findEdge(mesh,pt,adj,na,nb,1,NULL,&i) ) {
1183 return -1;
1184 }
1185
1186 if ( pt->xt ) {
1187 pxt = &mesh->xtetra[pt->xt];
1188 if ( (pxt->ftag[MMG5_ifar[i][0]] & MG_BDY) ||
1189 (pxt->ftag[MMG5_ifar[i][1]] & MG_BDY) ) {
1190 taginit = pxt->tag[i];
1191 pxt->tag[i] |= tag;
1192 /* Remove the potential nosurf tag if initially the edge is
1193 * really required */
1194 if ( ((taginit & MG_REQ) && !(taginit & MG_NOSURF)) ||
1195 (( tag & MG_REQ) && !( tag & MG_NOSURF)) ) {
1196 pxt->tag[i] &= ~MG_NOSURF;
1197 }
1198 pxt->edg[i] = MG_MAX(pxt->edg[i],edg);
1199 }
1200 }
1201 /* set new triangle for travel */
1202 adja = &mesh->adja[4*(adj-1)+1];
1203 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
1204 adj = adja[ MMG5_ifar[i][0] ] / 4;
1205 piv = pt->v[ MMG5_ifar[i][1] ];
1206 }
1207 else {
1208 adj = adja[ MMG5_ifar[i][1] ] /4;
1209 piv = pt->v[ MMG5_ifar[i][0] ];
1210 }
1211 }
1212 return adj;
1213}
1214
1228int MMG5_settag(MMG5_pMesh mesh,MMG5_int start,int ia,int16_t tag,int edg) {
1229 MMG5_pTetra pt;
1230 MMG5_pxTetra pxt;
1231 MMG5_int na,nb,*adja,adj,piv;
1232 int16_t taginit;
1233
1234 assert( start >= 1 );
1235 pt = &mesh->tetra[start];
1236 assert ( MG_EOK(pt) );
1237
1238 na = pt->v[ MMG5_iare[ia][0] ];
1239 nb = pt->v[ MMG5_iare[ia][1] ];
1240
1241 adja = &mesh->adja[4*(start-1)+1];
1242 adj = adja[MMG5_ifar[ia][0]] / 4;
1243 piv = pt->v[MMG5_ifar[ia][1]];
1244
1245 if ( pt->xt ) {
1246 pxt = &mesh->xtetra[pt->xt];
1247 if ( (pxt->ftag[MMG5_ifar[ia][0]] & MG_BDY) ||
1248 (pxt->ftag[MMG5_ifar[ia][1]] & MG_BDY) ) {
1249 taginit = pxt->tag[ia];
1250 pxt->tag[ia] |= tag;
1251 /* Remove the potential nosurf tag if initially the edge is
1252 * really required */
1253 if ( ((taginit & MG_REQ) && !(taginit & MG_NOSURF)) ||
1254 (( tag & MG_REQ) && !( tag & MG_NOSURF)) ) {
1255 pxt->tag[ia] &= ~MG_NOSURF;
1256 }
1257 pxt->edg[ia] = MG_MAX(pxt->edg[ia],edg);
1258 }
1259 }
1260
1261 adj = MMG3D_settag_oneDir(mesh,start,na,nb,tag,edg,piv,adj);
1262
1263 /* If all shell has been travelled, stop, else, travel it the other sense */
1264 if ( adj == start ) return 1;
1265 else if ( adj < 0 ) return 0;
1266
1267 assert(!adj);
1268
1269 pt = &mesh->tetra[start];
1270 adja = &mesh->adja[4*(start-1)+1];
1271 adj = adja[MMG5_ifar[ia][1]] / 4;
1272 piv = pt->v[MMG5_ifar[ia][0]];
1273
1274 adj = MMG3D_settag_oneDir(mesh,start,na,nb,tag,edg,piv,adj);
1275
1276 if ( adj < 0 ) return 0;
1277
1278 return 1;
1279}
1280
1296static inline
1297int MMG3D_deltag_oneDir(MMG5_pMesh mesh,MMG5_int start, MMG5_int na, MMG5_int nb,
1298 int16_t tag,MMG5_int piv,MMG5_int adj) {
1299 MMG5_pTetra pt;
1300 MMG5_pxTetra pxt;
1301 MMG5_int *adja;
1302 int8_t i;
1303
1304 while ( adj && (adj != start) ) {
1305 pt = &mesh->tetra[adj];
1306
1307 /* identification of edge number in tetra adj */
1308 if ( !MMG3D_findEdge(mesh,pt,adj,na,nb,1,NULL,&i) ) {
1309 return -1;
1310 }
1311
1312 if ( pt->xt ) {
1313 pxt = &mesh->xtetra[pt->xt];
1314 if ( (pxt->ftag[MMG5_ifar[i][0]] & MG_BDY) ||
1315 (pxt->ftag[MMG5_ifar[i][1]] & MG_BDY) ) {
1316 pxt->tag[i] &= ~tag;
1317 }
1318 }
1319 /* set new triangle for travel */
1320 adja = &mesh->adja[4*(adj-1)+1];
1321 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
1322 adj = adja[ MMG5_ifar[i][0] ] / 4;
1323 piv = pt->v[ MMG5_ifar[i][1] ];
1324 }
1325 else {
1326 adj = adja[ MMG5_ifar[i][1] ] /4;
1327 piv = pt->v[ MMG5_ifar[i][0] ];
1328 }
1329 }
1330 return adj;
1331}
1332
1344int MMG5_deltag(MMG5_pMesh mesh,MMG5_int start,int ia,int16_t tag) {
1345 MMG5_pTetra pt;
1346 MMG5_pxTetra pxt;
1347 MMG5_int na,nb,*adja,adj,piv;
1348 int8_t i;
1349
1350 assert( start >= 1 );
1351 pt = &mesh->tetra[start];
1352 assert ( MG_EOK(pt) );
1353
1354 na = pt->v[ MMG5_iare[ia][0] ];
1355 nb = pt->v[ MMG5_iare[ia][1] ];
1356
1357 adja = &mesh->adja[4*(start-1)+1];
1358 adj = adja[MMG5_ifar[ia][0]] / 4;
1359 piv = pt->v[MMG5_ifar[ia][1]];
1360
1361 if ( pt->xt ) {
1362 pxt = &mesh->xtetra[pt->xt];
1363 if ( (pxt->ftag[MMG5_ifar[ia][0]] & MG_BDY) ||
1364 (pxt->ftag[MMG5_ifar[ia][1]] & MG_BDY) ) {
1365 pxt->tag[ia] &= ~tag;
1366 }
1367 }
1368
1369 adj = MMG3D_deltag_oneDir(mesh,start,na,nb,tag,piv,adj);
1370
1371 /* If all shell has been travelled, stop, else, travel it the other sense */
1372 if ( adj == start ) return 1;
1373 else if ( adj < 0 ) return 0;
1374
1375 assert(!adj);
1376
1377 pt = &mesh->tetra[start];
1378 adja = &mesh->adja[4*(start-1)+1];
1379 adj = adja[MMG5_ifar[ia][1]] / 4;
1380 piv = pt->v[MMG5_ifar[ia][0]];
1381
1382 adj = MMG3D_deltag_oneDir(mesh,start,na,nb,tag,piv,adj);
1383
1384 if ( adj < 0 ) return 0;
1385
1386 return 1;
1387}
1388
1403int MMG5_coquil(MMG5_pMesh mesh,MMG5_int start,int ia,int64_t*list,int8_t *isbdy) {
1404 MMG5_pTetra pt;
1405 MMG5_int *adja,piv,na,nb,adj;
1406 int ilist;
1407 int8_t i;
1408 static int8_t mmgErr0=0, mmgErr1=0;
1409
1410 assert ( start >= 1 );
1411 pt = &mesh->tetra[start];
1412 assert ( MG_EOK(pt) );
1413
1414 na = pt->v[ MMG5_iare[ia][0] ];
1415 nb = pt->v[ MMG5_iare[ia][1] ];
1416 ilist = 0;
1417 list[ilist] = 6*(int64_t)start+ia;
1418 ilist++;
1419
1420 adja = &mesh->adja[4*(start-1)+1];
1421 adj = adja[MMG5_ifar[ia][0]] / 4; // start travelling by face (ia,0)
1422 piv = pt->v[MMG5_ifar[ia][1]];
1423 *isbdy = (pt->xt && (mesh->xtetra[pt->xt].ftag[MMG5_ifar[ia][0]] & MG_BDY))? 1 : 0;
1424
1425 while ( adj && (adj != start) ) {
1426 pt = &mesh->tetra[adj];
1427 if ( pt->tag & MG_REQ ) return 0;
1428
1429 /* identification of edge number in tetra adj */
1430 if ( !MMG3D_findEdge(mesh,pt,adj,na,nb,0,&mmgErr1,&i) ) return -1;
1431
1432 list[ilist] = 6*(int64_t)adj +i;
1433 ilist++;
1434 /* overflow */
1435 if ( ilist > MMG3D_LMAX-3 ) {
1436 if ( !mmgErr0 ) {
1437 fprintf(stderr,"\n ## Warning: %s: problem in remesh process."
1438 " Coquil of edge %" MMG5_PRId "-%" MMG5_PRId " contains too many elts.\n",
1439 __func__,MMG3D_indPt(mesh,na),MMG3D_indPt(mesh,nb));
1440 fprintf(stderr,"\n ## Try to modify the hausdorff number,"
1441 " or/and the maximum mesh.\n");
1442 mmgErr0 = 1;
1443 }
1444 return -1;
1445 }
1446
1447 /* set new triangle for travel */
1448 adja = &mesh->adja[4*(adj-1)+1];
1449 int8_t travel_fac = MMG5_ifar[i][0];
1450 if ( pt->v[ travel_fac ] == piv ) {
1451 adj = adja[ travel_fac ] / 4;
1452 piv = pt->v[ MMG5_ifar[i][1] ];
1453 }
1454 else {
1455 travel_fac = MMG5_ifar[i][1];
1456 assert(pt->v[ travel_fac ] == piv );
1457 adj = adja[ travel_fac ] /4;
1458 piv = pt->v[ MMG5_ifar[i][0] ];
1459 }
1460
1461 /* If we haven't cross yet a bdy face, test traveled triangle. Avoid the
1462 * test otherwise (to not add a useless access to the xtetra strcuture) */
1463 if ( !*isbdy ) {
1464 if ( pt->xt && (mesh->xtetra[pt->xt].ftag[travel_fac] & MG_BDY) ) {
1465 *isbdy = 1;
1466 }
1467 }
1468 }
1469
1470 /* At this point, the first travel, in one direction, of the shell is
1471 complete. Now, analyze why the travel ended. */
1472 if ( adj == start ) return 2*ilist;
1473 assert(!adj); // a boundary has been detected
1474
1475 adj = list[ilist-1] / 6;
1476 i = list[ilist-1] % 6;
1477 ilist = 0;
1478 *isbdy = 1;
1479
1480 /* Start back everything from this tetra adj */
1481 list[ilist] = 6*(int64_t)adj + i;
1482 ilist++;
1483 /* overflow */
1484 if ( ilist > MMG3D_LMAX-3 ) {
1485 if ( !mmgErr0 ) {
1486 fprintf(stderr,"\n ## Warning: %s: problem in remesh process."
1487 " Coquil of edge %" MMG5_PRId "-%" MMG5_PRId " contains too many elts.\n",
1488 __func__,MMG3D_indPt(mesh,na),MMG3D_indPt(mesh,nb));
1489 fprintf(stderr,"\n ## Try to modify the hausdorff number,"
1490 " or/and the maximum mesh.\n");
1491 mmgErr0 = 1;
1492 }
1493 return -1;
1494 }
1495
1496 adja = &mesh->adja[4*(adj-1)+1];
1497 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
1498 adj = adja[ MMG5_ifar[i][0] ];
1499 piv = pt->v[ MMG5_ifar[i][1] ];
1500 }
1501 else {
1502 adj = adja[ MMG5_ifar[i][1] ];
1503 piv = pt->v[ MMG5_ifar[i][0] ];
1504 }
1505
1506 while ( adj ) {
1507 adj /= 4;
1508 pt = &mesh->tetra[adj];
1509 if ( pt->tag & MG_REQ ) return 0;
1510
1511 /* identification of edge number in tetra adj */
1512 if ( !MMG3D_findEdge(mesh,pt,adj,na,nb,0,&mmgErr1,&i) ) return -1;
1513
1514 list[ilist] = 6*(int64_t)adj +i;
1515 ilist++;
1516 /* overflow */
1517 if ( ilist > MMG3D_LMAX-2 ) {
1518 if ( !mmgErr0 ) {
1519 fprintf(stderr,"\n ## Warning: %s: problem in remesh process."
1520 " Coquil of edge %" MMG5_PRId "-%" MMG5_PRId " contains too many elts.\n",
1521 __func__,MMG3D_indPt(mesh,na),MMG3D_indPt(mesh,nb));
1522 fprintf(stderr,"\n ## Try to modify the hausdorff number,"
1523 " or/and the maximum mesh.\n");
1524 mmgErr0 = 1;
1525 }
1526 return -1;
1527 }
1528
1529 /* set new triangle for travel */
1530 adja = &mesh->adja[4*(adj-1)+1];
1531 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
1532 adj = adja[ MMG5_ifar[i][0] ];
1533 piv = pt->v[ MMG5_ifar[i][1] ];
1534 }
1535 else {
1536 adj = adja[ MMG5_ifar[i][1] ];
1537 piv = pt->v[ MMG5_ifar[i][0] ];
1538 }
1539 }
1540 assert(!adj);
1541 return 2*ilist+1 ;
1542}
1543
1554int MMG5_srcbdy(MMG5_pMesh mesh,MMG5_int start,int ia) {
1555 MMG5_pTetra pt;
1556 MMG5_pxTetra pxt;
1557 MMG5_int na,nb,adj,piv,*adja;
1558 int8_t iadj,i;
1559
1560 pt = &mesh->tetra[start];
1561 na = pt->v[MMG5_iare[ia][0]];
1562 nb = pt->v[MMG5_iare[ia][1]];
1563
1564 adja = &mesh->adja[4*(start-1)+1];
1565 iadj = MMG5_ifar[ia][0];
1566
1567 if(pt->xt){
1568 pxt = &mesh->xtetra[pt->xt];
1569 if( pxt->ftag[iadj] & MG_BDY )
1570 return 1;
1571 }
1572
1573 adj = adja[iadj] / 4;
1574 piv = pt->v[MMG5_ifar[ia][1]];
1575
1576 while( adj && ( adj != start ) ) {
1577 pt = &mesh->tetra[adj];
1578
1579 /* identification of edge number in tetra adj */
1580 if ( !MMG3D_findEdge(mesh,pt,adj,na,nb,1,NULL,&i) ) return -1;
1581
1582 /* set new triangle for travel */
1583 adja = &mesh->adja[4*(adj-1)+1];
1584 if ( pt->v[ MMG5_ifar[i][0] ] == piv ) {
1585 iadj = MMG5_ifar[i][0];
1586 adj = adja[ iadj ] / 4;
1587 piv = pt->v[ MMG5_ifar[i][1] ];
1588 }
1589 else {
1590 iadj = MMG5_ifar[i][1];
1591 adj = adja[ iadj ] /4;
1592 piv = pt->v[ MMG5_ifar[i][0] ];
1593 }
1594
1595 if(pt->xt){
1596 pxt = &mesh->xtetra[pt->xt];
1597 if( pxt->ftag[iadj] & MG_BDY )
1598 return 1;
1599 }
1600 }
1601
1602 return 0;
1603}
1604
1613 void MMG5_coquilFaceErrorMessage(MMG5_pMesh mesh, MMG5_int k1, MMG5_int k2) {
1614 MMG5_pTetra pt;
1615 MMG5_int kel1, kel2;
1616 static int8_t mmgErr0;
1617
1618 if ( mmgErr0 ) return;
1619
1620 mmgErr0 = 1;
1621
1622 fprintf(stderr,"\n ## Error: %s: at least 1 problem in surface"
1623 " remesh process",__func__);
1624 fprintf(stderr," (potential creation of a lonely boundary face):\n");
1625
1626 kel1 = MMG3D_indElt(mesh,k1);
1627 kel2 = MMG3D_indElt(mesh,k2);
1628
1629 if ( kel1 != 0 ) {
1630 pt = &mesh->tetra[k1];
1631 assert ( pt && MG_EOK(pt) );
1632 fprintf(stderr," look at elt %" MMG5_PRId ":",kel1);
1633 fprintf(stderr," %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId ".\n", MMG3D_indPt(mesh,pt->v[0]),
1634 MMG3D_indPt(mesh,pt->v[1]),MMG3D_indPt(mesh,pt->v[2]),
1635 MMG3D_indPt(mesh,pt->v[3]));
1636 fprintf(stderr," adjacent tetras %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId "\n",
1637 MMG3D_indElt(mesh,mesh->adja[4*(k1-1)+1]/4),
1638 MMG3D_indElt(mesh,mesh->adja[4*(k1-1)+2]/4),
1639 MMG3D_indElt(mesh,mesh->adja[4*(k1-1)+3]/4),
1640 MMG3D_indElt(mesh,mesh->adja[4*(k1-1)+4]/4));
1641 fprintf(stderr," vertex required? %d %d %d %d\n",
1642 mesh->point[pt->v[0]].tag & MG_REQ,
1643 mesh->point[pt->v[1]].tag & MG_REQ,
1644 mesh->point[pt->v[2]].tag & MG_REQ,
1645 mesh->point[pt->v[3]].tag & MG_REQ);
1646 } else if ( kel2 != 0 ) {
1647 fprintf(stderr," look at elt %" MMG5_PRId ":",kel2);
1648 pt = &mesh->tetra[k2];
1649 assert ( pt && MG_EOK(pt) );
1650
1651 fprintf(stderr," %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId ".\n\n",MMG3D_indPt(mesh,pt->v[0]),
1652 MMG3D_indPt(mesh,pt->v[1]),MMG3D_indPt(mesh,pt->v[2]),
1653 MMG3D_indPt(mesh,pt->v[3]));
1654 }
1655 fprintf(stderr,"\n ## Try to modify the hausdorff number,");
1656 fprintf(stderr," the maximum mesh size or/and the value of angle detection.\n");
1657 fprintf(stderr," You can also try to run with -noswap option but probably");
1658 fprintf(stderr," the final mesh will have poor quality.\n\n");
1659}
1660
1686int MMG3D_coquilFaceFirstLoop(MMG5_pMesh mesh,MMG5_int start,MMG5_int na,MMG5_int nb,int8_t iface,
1687 int8_t ia,int64_t *list,int *ilist,MMG5_int *it1,MMG5_int *it2,
1688 MMG5_int *piv,MMG5_int *adj,int8_t *hasadja,int *nbdy,int silent) {
1689
1690 MMG5_pTetra pt;
1691 MMG5_int pradj,*adja;
1692 int pri,ier,ifar_idx;
1693 int8_t i;
1694 static int8_t mmgErr0 = 0;
1695
1696#ifndef NDEBUG
1697 MMG5_pxTetra pxt;
1698#endif
1699
1700 pt = &mesh->tetra[start];
1701
1702 *ilist = 0;
1703
1704 *it1 = 0;
1705 *it2 = 0;
1706
1707 /* Ensure that the first boundary face found is ifac (nedded in multidomain case) */
1708 ifar_idx = (MMG5_ifar[ia][0]==iface) ? 1 : 0;
1709 assert ( iface == MMG5_ifar[ia][(ifar_idx+1)%2] );
1710
1711 (*piv) = pt->v[MMG5_ifar[ia][ifar_idx]];
1712 *adj = start;
1713 i = ia;
1714
1715#ifndef NDEBUG
1716 pxt = &mesh->xtetra[pt->xt];
1717 assert ( MG_BDY & pxt->ftag[iface] );
1718#endif
1719
1720 (*it1) = 4*start + iface;
1721
1722 adja = &mesh->adja[4*(start-1)+1];
1723 (*hasadja) = (adja[iface] > 0);
1724
1725 (*nbdy) = 0;
1726
1727 do {
1728 pradj = (*adj);
1729 pri = i;
1730
1731 /* travel through new tetra */
1732 ier = MMG5_coquilTravel(mesh,na,nb,adj,piv,&iface,&i);
1733
1734 /* fill the shell */
1735 list[(*ilist)] = 6*(int64_t)pradj +pri;
1736 (*ilist)++;
1737
1738 /* overflow */
1739 if ( (*ilist) > MMG3D_LMAX-2 ) {
1740 if ( !mmgErr0 ) {
1741 fprintf(stderr,"\n ## Warning: %s: problem in remesh process."
1742 " Coquil of edge %" MMG5_PRId "-%" MMG5_PRId " contains too many elts.\n",
1743 __func__,MMG3D_indPt(mesh,na),MMG3D_indPt(mesh,nb));
1744 fprintf(stderr,"\n ## Try to modify the hausdorff number,"
1745 " or/and the maximum mesh.\n");
1746 mmgErr0 = 1;
1747 }
1748 return -1;
1749 }
1750
1751 if ( ier<0 ) return -1;
1752 else if ( !ier ) continue;
1753
1754 if ( !(*it2) ) {
1755 *it2 = 4*pradj+iface;
1756 (*nbdy)++;
1757 }
1758 else {
1759 (*nbdy)++;
1760 }
1761
1762 } while ( (*adj) && ((*adj) != start) );
1763
1764 if ( (*adj) != start ) {
1765 /* The starting boundary face has not been counted (open shell) */
1766 ++(*nbdy);
1767 }
1768
1769 return 1;
1770}
1771
1787void MMG3D_coquilFaceSecondLoopInit(MMG5_pMesh mesh,MMG5_int piv,int8_t *iface,
1788 int8_t *ia,int64_t *list,int *ilist,MMG5_int *it1,
1789 MMG5_int *pradj,MMG5_int *adj) {
1790
1791 MMG5_pTetra pt;
1792#ifndef NDEBUG
1793 MMG5_pxTetra pxt;
1794#endif
1795
1796 assert( !(*adj) );
1797
1798 (*adj) = list[(*ilist)-1] / 6;
1799 (*ia) = list[(*ilist)-1] % 6;
1800 (*ilist) = 0;
1801
1802 (*pradj) = (*adj);
1803 pt = &mesh->tetra[(*adj)];
1804#ifndef NDEBUG
1805 assert(pt->xt);
1806 pxt = &mesh->xtetra[pt->xt];
1807#endif
1808
1809 if ( pt->v[ MMG5_ifar[(*ia)][0] ] == piv ) {
1810 (*iface) = MMG5_ifar[(*ia)][1];
1811 }
1812 else {
1813 (*iface) = MMG5_ifar[(*ia)][0];
1814 }
1815
1816 assert ( pxt->ftag[(*iface)] & MG_BDY );
1817
1818 *it1 = 4*(*pradj) + (*iface);
1819
1820}
1821
1843int MMG5_coquilface(MMG5_pMesh mesh,MMG5_int start,int8_t iface,int ia,int64_t *list,
1844 MMG5_int *it1,MMG5_int *it2, int silent) {
1845 MMG5_pTetra pt;
1846 MMG5_int piv,adj,na,nb,pradj;
1847 int ier,nbdy,ilist;
1848 int8_t hasadja,i;
1849 static int8_t mmgErr0=0,mmgErr1=0,mmgWarn0=0;
1850
1851 pt = &mesh->tetra[start];
1852
1853 na = pt->v[ MMG5_iare[ia][0] ];
1854 nb = pt->v[ MMG5_iare[ia][1] ];
1855
1856 /* Travel throug the shell of the edge until reaching a tetra without adjacent
1857 * or until reaching the starting tetra */
1858 ier = MMG3D_coquilFaceFirstLoop(mesh,start,na,nb,iface,ia,list,&ilist,it1,it2,
1859 &piv,&adj,&hasadja,&nbdy,silent);
1860
1861 if ( ier < 0 ) return ier;
1862
1863 /* At this point, the first travel, in one direction, of the shell is
1864 complete. Now, analyze why the travel ended. */
1865 if ( adj == start ) {
1866 if ( !(*it2) ) {
1867 if ( !mmgErr0 ) {
1868 printf(" ## Error: %s: Wrong boundary tags: Only 1 boundary face found in"
1869 " the shell of the edge\n",__func__);
1870 mmgErr0 = 1;
1871 }
1872 return -1;
1873 }
1874
1875 if ( nbdy != 2 ) {
1876 if ( nbdy < 2 ) {
1877 MMG5_coquilFaceErrorMessage(mesh, (*it1)/4, (*it2)/4);
1878 return -1;
1879 }
1880
1881 if ( !silent ) {
1882 if ( !mmgWarn0 ) {
1883 // Algiane: for a manifold edge 2 cases :
1884 // 1) the shell is open and we have more than 3 tri sharing the edge
1885 // (highly non-manifold)
1886 // 2) we have a non-manifold shape immersed in a domain (3 triangles
1887 // sharing the edge and a closed shell)
1888 printf(" ## Warning: %s: you have %d boundary triangles in the closed shell"
1889 " of a manifold edge.\n",__func__,nbdy);
1890 printf(" Problem may occur during remesh process.\n");
1891 mmgWarn0 = 1;
1892
1893 /* MMG5_coquilface is called only on edges marked as manifold, check this */
1894 assert ( pt->xt );
1895 assert ( !(mesh->xtetra[pt->xt].tag[ia] & MG_NOM) );
1896 }
1897 }
1898 }
1899
1900 return (2*ilist);
1901 }
1902
1903 /* A boundary has been detected : slightly different configuration */
1904 if ( !hasadja ) return 2*ilist+1;
1905
1906 /* Start back everything from this tetra adj */
1907 MMG3D_coquilFaceSecondLoopInit(mesh,piv,&iface,&i,list,&ilist,it1,
1908 &pradj,&adj);
1909
1910 while ( adj ) {
1911 pradj = adj;
1912
1913 ier = MMG5_openCoquilTravel( mesh, na, nb, &adj, &piv, &iface, &i );
1914 if ( ier<0 ) return -1;
1915
1916 list[ilist] = 6*(int64_t)pradj +i;
1917 ilist++;
1918 /* overflow */
1919 if ( ilist > MMG3D_LMAX-2 ) {
1920 if ( !mmgErr1 ) {
1921 fprintf(stderr,"\n ## Warning: %s: problem in remesh process."
1922 " Coquil of edge %" MMG5_PRId "-%" MMG5_PRId " contains too many elts.\n",
1923 __func__,MMG3D_indPt(mesh,na),MMG3D_indPt(mesh,nb));
1924 fprintf(stderr,"\n ## Try to modify the hausdorff number,"
1925 " or/and the maximum mesh.\n");
1926 mmgErr1 = 1;
1927 }
1928 return -1;
1929 }
1930 }
1931
1932 assert(!adj);
1933 *it2 = 4*pradj + iface;
1934
1935 if ( (!(*it1) || !(*it2)) || ((*it1) == (*it2)) ) {
1936 MMG5_coquilFaceErrorMessage(mesh, (*it1)/4, (*it2)/4);
1937 return -1;
1938 }
1939 return 2*ilist+1;
1940}
1941
1959int16_t MMG5_coquilTravel(MMG5_pMesh mesh, MMG5_int na, MMG5_int nb, MMG5_int* adj, MMG5_int *piv,
1960 int8_t *iface, int8_t *i )
1961{
1962 MMG5_pTetra pt;
1963 MMG5_pxTetra pxt;
1964 MMG5_int *adja;
1965 int16_t isbdy;
1966
1967 pt = &mesh->tetra[*adj];
1968 pxt = &mesh->xtetra[pt->xt];
1969
1970 /* set new tetra for travel */
1971 adja = &mesh->adja[4*(*adj-1)+1];
1972 if ( pt->v[ MMG5_ifar[*i][0] ] == *piv ) {
1973 *iface = MMG5_ifar[*i][0];
1974 *adj = adja[ MMG5_ifar[*i][0] ] / 4;
1975 *piv = pt->v[ MMG5_ifar[*i][1] ];
1976 }
1977 else {
1978 assert(pt->v[ MMG5_ifar[*i][1] ] == *piv );
1979 *iface = MMG5_ifar[*i][1];
1980 *adj = adja[ MMG5_ifar[*i][1] ] /4;
1981 *piv = pt->v[ MMG5_ifar[*i][0] ];
1982 }
1983 isbdy = pt->xt ? (pxt->ftag[*iface] & MG_BDY) : 0;
1984
1985 /* identification of edge number in tetra *adj */
1986 if ( *adj ) {
1987 pt = &mesh->tetra[*adj];
1988 if ( !MMG3D_findEdge(mesh,pt,*adj,na,nb,1,NULL,i) ) return -1;
1989 }
1990
1991 return isbdy;
1992}
1993
2011int16_t MMG5_openCoquilTravel(MMG5_pMesh mesh,MMG5_int na,MMG5_int nb,MMG5_int* adj,MMG5_int *piv,
2012 int8_t *iface, int8_t *i )
2013{
2014 MMG5_pTetra pt;
2015 MMG5_int *adja;
2016
2017 pt = &mesh->tetra[*adj];
2018
2019 /* identification of edge number in tetra *adj */
2020 if ( !MMG3D_findEdge(mesh,pt,*adj,na,nb,1,NULL,i) ) return 0;
2021
2022 /* set new tetra for travel */
2023 adja = &mesh->adja[4*(*adj-1)+1];
2024 if ( pt->v[ MMG5_ifar[*i][0] ] == *piv ) {
2025 *iface = MMG5_ifar[*i][0];
2026 *adj = adja[ *iface ] / 4;
2027 *piv = pt->v[ MMG5_ifar[*i][1] ];
2028 }
2029 else {
2030 assert(pt->v[ MMG5_ifar[*i][1] ] == *piv );
2031 *iface = MMG5_ifar[*i][1];
2032 *adj = adja[ *iface ] /4;
2033 *piv = pt->v[ MMG5_ifar[*i][0] ];
2034 }
2035
2036 return 1;
2037}
int ier
if(!ier) exit(EXIT_FAILURE)
MMG5_pMesh * mesh
int MMG5_settag(MMG5_pMesh mesh, MMG5_int start, int ia, int16_t tag, int edg)
Definition: boulep_3d.c:1228
int16_t MMG5_coquilTravel(MMG5_pMesh mesh, MMG5_int na, MMG5_int nb, MMG5_int *adj, MMG5_int *piv, int8_t *iface, int8_t *i)
Definition: boulep_3d.c:1959
int MMG5_deltag(MMG5_pMesh mesh, MMG5_int start, int ia, int16_t tag)
Definition: boulep_3d.c:1344
int MMG5_boulevolp(MMG5_pMesh mesh, MMG5_int start, int ip, int64_t *list)
Definition: boulep_3d.c:54
int MMG5_boulesurfvolp(MMG5_pMesh mesh, MMG5_int start, int ip, int iface, int64_t *listv, int *ilistv, MMG5_int *lists, int *ilists, int isnm)
Definition: boulep_3d.c:607
void MMG3D_coquilFaceSecondLoopInit(MMG5_pMesh mesh, MMG5_int piv, int8_t *iface, int8_t *ia, int64_t *list, int *ilist, MMG5_int *it1, MMG5_int *pradj, MMG5_int *adj)
Definition: boulep_3d.c:1787
int MMG3D_findEdge(MMG5_pMesh mesh, MMG5_pTetra pt, MMG5_int k, MMG5_int na, MMG5_int nb, int error, int8_t *mmgWarn, int8_t *ia)
Definition: boulep_3d.c:113
int MMG3D_coquilFaceFirstLoop(MMG5_pMesh mesh, MMG5_int start, MMG5_int na, MMG5_int nb, int8_t iface, int8_t ia, int64_t *list, int *ilist, MMG5_int *it1, MMG5_int *it2, MMG5_int *piv, MMG5_int *adj, int8_t *hasadja, int *nbdy, int silent)
Definition: boulep_3d.c:1686
MMG5_Info info
void MMG5_coquilFaceErrorMessage(MMG5_pMesh mesh, MMG5_int k1, MMG5_int k2)
Definition: boulep_3d.c:1613
int16_t MMG5_openCoquilTravel(MMG5_pMesh mesh, MMG5_int na, MMG5_int nb, MMG5_int *adj, MMG5_int *piv, int8_t *iface, int8_t *i)
Definition: boulep_3d.c:2011
int MMG5_boulenm(MMG5_pMesh mesh, MMG5_int start, int ip, int iface, double n[3], double t[3])
Definition: boulep_3d.c:196
int MMG5_boulesurfvolpNom(MMG5_pMesh mesh, MMG5_int start, int ip, int iface, int64_t *listv, int *ilistv, MMG5_int *lists, int *ilists, MMG5_int *refmin, MMG5_int *refplus, int isnm)
Definition: boulep_3d.c:771
int MMG5_bouletrid(MMG5_pMesh mesh, MMG5_int start, int iface, int ip, int *il1, MMG5_int *l1, int *il2, MMG5_int *l2, MMG5_int *ip0, MMG5_int *ip1)
Definition: boulep_3d.c:952
int MMG5_srcbdy(MMG5_pMesh mesh, MMG5_int start, int ia)
Definition: boulep_3d.c:1554
int MMG5_boulernm(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int start, int ip, MMG5_int *ng, MMG5_int *nr, MMG5_int *nm)
Definition: boulep_3d.c:455
int MMG5_coquilface(MMG5_pMesh mesh, MMG5_int start, int8_t iface, int ia, int64_t *list, MMG5_int *it1, MMG5_int *it2, int silent)
Definition: boulep_3d.c:1843
int MMG5_coquil(MMG5_pMesh mesh, MMG5_int start, int ia, int64_t *list, int8_t *isbdy)
Definition: boulep_3d.c:1403
static int MMG3D_settag_oneDir(MMG5_pMesh mesh, MMG5_int start, MMG5_int na, MMG5_int nb, int16_t tag, int edg, MMG5_int piv, MMG5_int adj)
Definition: boulep_3d.c:1170
static void MMG3D_compute_tangent(MMG5_pMesh mesh, int nump, int ip0, int ip1, double t[3])
Definition: boulep_3d.c:146
int MMG5_boulenmInt(MMG5_pMesh mesh, MMG5_int start, int ip, double t[3])
Definition: boulep_3d.c:342
static int MMG3D_deltag_oneDir(MMG5_pMesh mesh, MMG5_int start, MMG5_int na, MMG5_int nb, int16_t tag, MMG5_int piv, MMG5_int adj)
Definition: boulep_3d.c:1297
API headers for the mmg3d library.
#define MMG3D_LMAX
Definition: libmmg3d.h:58
static const int8_t MMG5_idirinv[4][4]
MMG5_int MMG3D_indPt(MMG5_pMesh mesh, MMG5_int kp)
Definition: tools_3d.c:916
static const uint8_t MMG5_arpt[4][3]
arpt[i]: edges passing through vertex i
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
static const uint8_t MMG5_ifar[6][2]
ifar[i][]: faces sharing the ith edge of the tetra
static const uint8_t MMG5_inxt3[7]
next vertex of tetra: {1,2,3,0,1,2,3}
int MMG5_norface(MMG5_pMesh mesh, MMG5_int k, int iface, double v[3])
Definition: tools_3d.c:52
static const uint8_t MMG5_idir[4][3]
idir[i]: vertices of face opposite to vertex i
MMG5_int MMG3D_indElt(MMG5_pMesh mesh, MMG5_int kel)
Definition: tools_3d.c:860
#define MG_REQ
#define MG_GEO
#define MG_EOK(pt)
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#define MMG5_GAP
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
#define MMG5_KB
#define MMG5_TAB_RECALLOC(mesh, ptr, initSize, wantedGap, type, message, law)
#define MG_GET(flag, bit)
static const uint8_t MMG5_inxt2[6]
#define MG_BDY
#define MG_NOSURF
#define MG_NOM
int MMG5_norpts(MMG5_pMesh, MMG5_int, MMG5_int, MMG5_int, double *)
Definition: tools.c:183
#define MMG5_EPSD2
#define MMG5_KA
#define MG_REF
Identic as MMG5_HGeom but use MMG5_hedge to store edges instead of MMG5_hgeom (memory economy).
Definition: libmmgtypes.h:595
MMG5_int max
Definition: libmmgtypes.h:596
MMG5_int nxt
Definition: libmmgtypes.h:596
MMG5_hedge * item
Definition: libmmgtypes.h:597
MMG5_int siz
Definition: libmmgtypes.h:596
Store input parameters of the run.
Definition: libmmgtypes.h:516
int8_t ddebug
Definition: libmmgtypes.h:532
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_int * adja
Definition: libmmgtypes.h:624
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:642
MMG5_int base
Definition: libmmgtypes.h:616
MMG5_pTetra tetra
Definition: libmmgtypes.h:643
MMG5_pxTetra xtetra
Definition: libmmgtypes.h:644
Structure to store points of a MMG mesh.
Definition: libmmgtypes.h:270
int16_t tag
Definition: libmmgtypes.h:284
double c[3]
Definition: libmmgtypes.h:271
MMG5_int xp
Definition: libmmgtypes.h:279
MMG5_int v[4]
Definition: libmmgtypes.h:403
MMG5_int xt
Definition: libmmgtypes.h:407
MMG5_int flag
Definition: libmmgtypes.h:409
MMG5_int ref
Definition: libmmgtypes.h:404
int16_t tag
Definition: libmmgtypes.h:410
Used to hash edges (memory economy compared to MMG5_hgeom).
Definition: libmmgtypes.h:584
MMG5_int b
Definition: libmmgtypes.h:585
MMG5_int a
Definition: libmmgtypes.h:585
MMG5_int nxt
Definition: libmmgtypes.h:585
double n2[3]
Definition: libmmgtypes.h:295
double n1[3]
Definition: libmmgtypes.h:295
Structure to store the surface tetrahedra of a MMG mesh.
Definition: libmmgtypes.h:418
int16_t ftag[4]
Definition: libmmgtypes.h:423
int16_t tag[6]
Definition: libmmgtypes.h:425
int8_t ori
Definition: libmmgtypes.h:427
MMG5_int edg[6]
Definition: libmmgtypes.h:421