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