Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
mmg3d2.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"
39
40extern int8_t ddb;
41
57static inline
58double MMG3D_vfrac_1vertex(MMG5_pPoint ppt[4],int8_t i0,double v[4],int8_t part_opp) {
59 double vfrac,lam,area,o1[3],o2[3],o3[3];
60 int8_t i1,i2,i3;
61
62 i1 = MMG5_idir[i0][0];
63 i2 = MMG5_idir[i0][1];
64 i3 = MMG5_idir[i0][2];
65
66 lam = v[i0] / (v[i0]-v[i1]);
67 o1[0] = ppt[i0]->c[0] + lam*(ppt[i1]->c[0]-ppt[i0]->c[0]);
68 o1[1] = ppt[i0]->c[1] + lam*(ppt[i1]->c[1]-ppt[i0]->c[1]);
69 o1[2] = ppt[i0]->c[2] + lam*(ppt[i1]->c[2]-ppt[i0]->c[2]);
70
71 lam = v[i0] / (v[i0]-v[i2]);
72 o2[0] = ppt[i0]->c[0] + lam*(ppt[i2]->c[0]-ppt[i0]->c[0]);
73 o2[1] = ppt[i0]->c[1] + lam*(ppt[i2]->c[1]-ppt[i0]->c[1]);
74 o2[2] = ppt[i0]->c[2] + lam*(ppt[i2]->c[2]-ppt[i0]->c[2]);
75
76 lam = v[i0] / (v[i0]-v[i3]);
77 o3[0] = ppt[i0]->c[0] + lam*(ppt[i3]->c[0]-ppt[i0]->c[0]);
78 o3[1] = ppt[i0]->c[1] + lam*(ppt[i3]->c[1]-ppt[i0]->c[1]);
79 o3[2] = ppt[i0]->c[2] + lam*(ppt[i3]->c[2]-ppt[i0]->c[2]);
80
81 vfrac = fabs (MMG5_det4pt(ppt[i0]->c,o1,o2,o3));
82
83 if ( !part_opp ) {
84 return vfrac;
85 }
86 else {
87 area = MMG5_det4pt(ppt[0]->c,ppt[1]->c,ppt[2]->c,ppt[3]->c);
88 vfrac = fabs(area) - vfrac;
89 return vfrac;
90 }
91
92 /* Should not pass here */
93 return 0.0;
94}
95
96
107double MMG3D_vfrac(MMG5_pMesh mesh,MMG5_pSol sol,MMG5_int k,int pm) {
108 MMG5_pTetra pt;
109 MMG5_pPoint ppt[4];
110 double v[4],vfm,vfp,lam,eps,o[18];
111 int nplus,nminus,nzero;
112 MMG5_int flag,ip[4];
113 int8_t cfg,ia;
114 int8_t i,i0,i1,imin1,imin2,iplus1,iplus2,iz;
115 uint8_t tau[4];
116 const uint8_t *taued;
117
118 eps = MMG5_EPS*MMG5_EPS;
119 pt = &mesh->tetra[k];
120
121 ip[0] = pt->v[0];
122 ip[1] = pt->v[1];
123 ip[2] = pt->v[2];
124 ip[3] = pt->v[3];
125
126 ppt[0] = &mesh->point[ip[0]];
127 ppt[1] = &mesh->point[ip[1]];
128 ppt[2] = &mesh->point[ip[2]];
129 ppt[3] = &mesh->point[ip[3]];
130
131 v[0] = sol->m[ip[0]];
132 v[1] = sol->m[ip[1]];
133 v[2] = sol->m[ip[2]];
134 v[3] = sol->m[ip[3]];
135
136 /* Identify number of zero, positive and negative vertices, and corresponding
137 * indices */
138 nplus = nminus = nzero = 0;
139 imin1 = imin2 = iplus1 = iplus2 = iz = -1;
140
141 for (i=0; i<4; i++) {
142 if ( fabs(v[i]) < eps ) {
143 nzero++;
144 if ( iz < 0 ) iz = i;
145 }
146 else if ( v[i] >= eps ) {
147 nplus++;
148 if ( iplus1 < 0 ) iplus1 = i;
149 else if ( iplus2 < 0 ) iplus2 = i;
150 }
151 else {
152 nminus++;
153 if ( imin1 < 0 ) imin1 = i;
154 else if ( imin2 < 0 ) imin2 = i;
155 }
156 }
157
158 /* Degenerate case */
159 if ( nzero == 4 ) return 0.0;
160
161 /* Whole tetra is positive */
162 if ( nminus == 0 ) {
163 vfp = MMG5_det4pt(ppt[0]->c,ppt[1]->c,ppt[2]->c,ppt[3]->c);
164 vfp = fabs(vfp);
165 if ( pm == 1 ) return vfp;
166 else return 0.0;
167 }
168
169 /* Whole tetra is negative */
170 if ( nplus == 0 ) {
171 vfm = MMG5_det4pt(ppt[0]->c,ppt[1]->c,ppt[2]->c,ppt[3]->c);
172 vfm = fabs(vfm);
173 if ( pm == -1 ) return vfm;
174 else return 0.0;
175 }
176
177 /* Exactly one vertex is negative */
178 if ( nminus == 1 ) {
179 return MMG3D_vfrac_1vertex(ppt,imin1,v,pm!=-1);
180 }
181
182 /* Exactly one vertex is positive */
183 if ( nplus == 1 ) {
184 return MMG3D_vfrac_1vertex(ppt,iplus1,v,pm!=1);
185 }
186
187 flag = 0;
188 for ( ia=0; ia<18; ++ia ) {
189 o[ia] = 0.0;
190 }
191
192 /* We have exactly 2 negative vertices and 2 positive ones */
193 assert ( nplus==2 && nminus==2 );
194
195 /* Config detection */
196 for ( ia=0; ia<6; ++ia ) {
197 i0 = MMG5_iare[ia][0];
198 i1 = MMG5_iare[ia][1];
199
200 if ( fabs(v[i0]) < MMG5_EPSD2 || fabs(v[i1]) < MMG5_EPSD2 ) continue;
201 else if ( MG_SMSGN(v[i0],v[i1]) ) continue;
202
203 MG_SET(flag,ia);
204
205 /* Computation of the intersection between edges and isovalue */
206 lam = v[i0] / (v[i0]-v[i1]);
207 o[3*ia ] = ppt[i0]->c[0] + lam*(ppt[i1]->c[0]-ppt[i0]->c[0]);
208 o[3*ia+1] = ppt[i0]->c[1] + lam*(ppt[i1]->c[1]-ppt[i0]->c[1]);
209 o[3*ia+2] = ppt[i0]->c[2] + lam*(ppt[i1]->c[2]-ppt[i0]->c[2]);
210 }
211
212 assert ( flag==30 || flag==45 || flag==51 );
213
214 /* Set permutation of vertices : reference configuration 30 */
215 tau[0] = 0 ; tau[1] = 1 ; tau[2] = 2 ; tau[3] = 3;
216 taued = &MMG5_permedge[0][0];
217
218 switch(flag){
219 case 45:
220 tau[0] = 1 ; tau[1] = 3 ; tau[2] = 2 ; tau[3] = 0;
221 taued = &MMG5_permedge[5][0];
222 break;
223
224 case 51:
225 tau[0] = 1 ; tau[1] = 2 ; tau[2] = 0 ; tau[3] = 3;
226 taued = &MMG5_permedge[4][0];
227 break;
228 }
229
230 if ( pm < 0 ) {
231 if ( v[tau[0]] < 0.0 ) {
232 /* compute the area that contains tau[0] and tau[1] */
233 cfg = 0;
234 }
235 else {
236 /* compute the area that contains tau[2] and tau[3] */
237 cfg = 2;
238 }
239 }
240 else {
241 assert ( pm > 0 );
242 if ( v[tau[0]] < 0.0 ) {
243 /* compute the area that contains tau[0] and tau[1] */
244 cfg = 2;
245 }
246 else {
247 cfg = 0;
248 }
249 }
250 assert ( cfg == 0 || cfg == 2 );
251
252 /* Computation of the area depending on the detected config */
253 if ( cfg == 0 ) {
254 vfp = fabs ( MMG5_det4pt(ppt[tau[0]]->c,ppt[tau[1]]->c,&o[3*taued[3]],&o[3*taued[4]]) );
255 vfp += fabs ( MMG5_det4pt(ppt[tau[0]]->c,&o[3*taued[4]],&o[3*taued[3]],&o[3*taued[2]]) );
256 vfp += fabs ( MMG5_det4pt(ppt[tau[0]]->c,&o[3*taued[3]],&o[3*taued[1]],&o[3*taued[2]]) );
257#ifdef NDEBUG
258 return vfp;
259#endif
260 }
261 else if ( cfg == 2 ) {
262 vfm = fabs ( MMG5_det4pt(&o[3*taued[2]],&o[3*taued[4]],ppt[tau[2]]->c,ppt[tau[3]]->c) );
263 vfm += fabs ( MMG5_det4pt(&o[3*taued[2]],&o[3*taued[3]],ppt[tau[2]]->c,&o[3*taued[4]]) );
264 vfm += fabs ( MMG5_det4pt(&o[3*taued[1]],&o[3*taued[3]],ppt[tau[2]]->c,&o[3*taued[2]]) );
265#ifdef NDEBUG
266 return vfm;
267#endif
268 }
269
270#ifndef NDEBUG
272 /* Compute the complementary area */
273 if ( cfg == 0 ) {
274 vfm = fabs ( MMG5_det4pt(&o[3*taued[2]],&o[3*taued[4]],ppt[tau[2]]->c,ppt[tau[3]]->c) );
275 vfm += fabs ( MMG5_det4pt(&o[3*taued[2]],&o[3*taued[3]],ppt[tau[2]]->c,&o[3*taued[4]]) );
276 vfm += fabs ( MMG5_det4pt(&o[3*taued[1]],&o[3*taued[3]],ppt[tau[2]]->c,&o[3*taued[2]]) );
277 }
278 else if ( cfg == 2 ) {
279 vfp = fabs ( MMG5_det4pt(ppt[tau[0]]->c,ppt[tau[1]]->c,&o[3*taued[3]],&o[3*taued[4]]) );
280 vfp += fabs ( MMG5_det4pt(ppt[tau[0]]->c,&o[3*taued[4]],&o[3*taued[3]],&o[3*taued[2]]) );
281 vfp += fabs ( MMG5_det4pt(ppt[tau[0]]->c,&o[3*taued[3]],&o[3*taued[1]],&o[3*taued[2]]) );
282 }
283
284 /* vfp and vfm have been computed: check that the sum of both area is the
285 * area of the whole tetra */
286 double vf;
287 vf = fabs ( MMG5_det4pt(ppt[0]->c,ppt[1]->c,ppt[2]->c,ppt[3]->c) );
288
289 assert ( fabs(vf-(vfp+vfm)) < MMG5_EPSOK );
290
291 if ( cfg==0 ) {
292 return vfp;
293 }
294 else {
295 return vfm;
296 }
297#endif
298
299 /* Should not pass here */
300 return 0.0;
301}
302
314 MMG5_pTetra pt;
315 MMG5_pPoint p0;
316 MMG5_int k,ref;
317 int8_t i;
318
319 /* Travel edges and reset tags at edges extremities */
320 /* Reset ref and tags at ISO points */
321 for (k=1; k<=mesh->ne; k++) {
322 pt = &mesh->tetra[k];
323 if ( !MG_EOK(pt) ) continue;
324
325 for (i=0; i<4; i++) {
326 p0 = &mesh->point[pt->v[i]];
327 /* Reset triangles */
328
329 /* Reset vertices */
330 if ( p0->ref == mesh->info.isoref ) {
331 p0->ref = 0;
332 /* Reset tags */
333 p0->tag &= ~MG_CRN;
334 p0->tag &= ~MG_REQ;
335 }
336 }
337 }
338
339 /* Reset the tetra references to their initial distribution */
340 for ( k=1; k<=mesh->ne; k++ ) {
341 pt = &mesh->tetra[k];
342
343 if ( !MG_EOK(pt) ) continue;
344
345 /* If no material map is provided, reference is resetted to 0, otherwise,
346 * reference has to exist in the material map because it is not possible to
347 * decide for the user if a ref that is not listed has to be preserved or
348 * resetted to 0 */
349 if( !MMG5_getStartRef(mesh,pt->ref,&ref) ) return 0;
350 pt->ref = ref;
351 }
352
353 return 1;
354}
355
356
363static inline int
364MMG5_invsl(double A[3][3],double b[3],double r[3]) {
365 double detA;
366
367 detA = A[0][0]*(A[1][1]*A[2][2] - A[2][1]*A[1][2]) \
368 - A[0][1]*(A[1][0]*A[2][2] - A[2][0]*A[1][2]) \
369 + A[0][2]*(A[1][0]*A[2][1] - A[2][0]*A[1][1]);
370 if ( detA < MMG5_EPSD ) return 0;
371 detA = 1.0 / detA;
372
373 r[0] = b[0]*(A[1][1]*A[2][2] - A[2][1]*A[1][2]) \
374 - A[0][1]*(b[1]*A[2][2] - b[2]*A[1][2]) \
375 + A[0][2]*(b[1]*A[2][1] - b[2]*A[1][1]);
376
377 r[1] = A[0][0]*(b[1]*A[2][2] - b[2]*A[1][2]) \
378 - b[0]*(A[1][0]*A[2][2] - A[2][0]*A[1][2]) \
379 + A[0][2]*(A[1][0]*b[2] - A[2][0]*b[1]);
380
381 r[2] = A[0][0]*(A[1][1]*b[2] - A[2][1]*b[1]) \
382 - A[0][1]*(A[1][0]*b[2] - A[2][0]*b[1]) \
383 + b[0]*(A[1][0]*A[2][1] - A[2][0]*A[1][1]);
384
385 r[0] *= detA;
386 r[1] *= detA;
387 r[2] *= detA;
388
389 return 1;
390}
391
407int MMG3D_ismaniball(MMG5_pMesh mesh,MMG5_pSol sol,MMG5_int k,int indp) {
408 MMG5_pTetra pt,pt1;
409 double v,v0,v1,v2;
410 int ibdy,ilist,cur,l;
411 MMG5_int *adja,list[MMG3D_LMAX+1],bdy[MMG3D_LMAX+1],jel,np,iel,res,base;
412 int8_t i,i0,i1,i2,j0,j1,j2,j,ip,nzeros,nopp,nsame;
413 static int8_t mmgWarn0 = 0;
414
415 pt = &mesh->tetra[k];
416 np = pt->v[indp];
417 if ( fabs(sol->m[np]) > MMG5_EPSD2 ) return 1;
418
419 memset(bdy,0,(MMG3D_LMAX+1)*sizeof(MMG5_int));
420 memset(list,0,(MMG3D_LMAX+1)*sizeof(MMG5_int));
421
422 /* Sign of a starting point in ball of np */
423 for (j=0; j<3; j++) {
424 ip = MMG5_idir[indp][j];
425 if ( sol->m[pt->v[ip]] != 0.0 ) break;
426 }
427 if ( j == 3 ) {
428 if ( !mmgWarn0 ) {
429 mmgWarn0 = 1;
430 fprintf(stderr,"\n ## Warning: %s: at least 1 tetra with 4 null"
431 " values.\n",__func__);
432 }
433 return 0;
434 }
435
436 v = sol->m[pt->v[ip]];
437 base = ++mesh->base;
438 pt->flag = base;
439 ilist = 0;
440 list[ilist] = 4*k+indp;
441 ilist++;
442
443 /* travel list and pile up, by adjacency, faces of ball of np while they have at least
444 a vertex with same sign as v */
445 res = cur = 0;
446 while ( cur < ilist ) {
447 iel = list[cur] / 4;
448 i = list[cur] % 4;
449 pt = &mesh->tetra[iel];
450 adja = &mesh->adja[4*(iel-1)+1];
451
452 /* Store a face for starting back enumeration with the opposite sign */
453 if ( !res ) {
454 for (j=0; j<3; j++) {
455 i1 = MMG5_idir[i][j];
456 v1 = sol->m[pt->v[i1]];
457 if ( ( v1 != 0.0 ) && !MG_SMSGN(v,v1) ) {
458 res = 4*iel + i;
459 break;
460 }
461 }
462 }
463
464 /* Pile up faces sharing a vertex with same sign as v */
465 for (j=0; j<3; j++) {
466 i1 = MMG5_idir[i][MMG5_inxt2[j]];
467 i2 = MMG5_idir[i][MMG5_iprv2[j]];
468 v1 = sol->m[pt->v[i1]];
469 v2 = sol->m[pt->v[i2]];
470
471 if ( ( ( v1 != 0.0 ) && MG_SMSGN(v,v1) ) ||
472 ( ( v2 != 0.0 ) && MG_SMSGN(v,v2) ) ) {
473 jel = adja[MMG5_idir[i][j]];
474 if( !jel ) continue;
475
476 jel /= 4;
477 pt1 = &mesh->tetra[jel];
478
479 if ( pt1->flag == base ) continue;
480 for (ip=0; ip<4; ip++) {
481 if ( pt1->v[ip] == np ) break;
482 }
483 assert( ip < 4 );
484 pt1->flag = base;
485 list[ilist] = 4*jel + ip;
486 ilist++;
487 assert(ilist < MMG3D_LMAX);
488 }
489 }
490 cur++;
491 }
492
493 /* Fill in list bdy, corresponding to the support tetras of the boundary to be created */
494 ibdy = 0;
495 for(l=0; l<ilist; l++) {
496 iel = list[l] / 4;
497 i = list[l] % 4;
498 pt = &mesh->tetra[iel];
499
500 nzeros = nsame = nopp = 0;
501
502 i0 = MMG5_idir[i][0];
503 i1 = MMG5_idir[i][1];
504 i2 = MMG5_idir[i][2];
505
506 v0 = sol->m[pt->v[i0]];
507 v1 = sol->m[pt->v[i1]];
508 v2 = sol->m[pt->v[i2]];
509
510 if ( v0 == 0.0 )
511 nzeros++;
512 else if ( MG_SMSGN(v,v0) )
513 nsame++;
514 else
515 nopp++;
516
517 if ( v1 == 0.0 )
518 nzeros++;
519 else if ( MG_SMSGN(v,v1) )
520 nsame++;
521 else
522 nopp++;
523
524 if ( v2 == 0.0 )
525 nzeros++;
526 else if ( MG_SMSGN(v,v2) )
527 nsame++;
528 else
529 nopp++;
530
531 /* If no starting face with one vertex with opposite sign to v has been found,
532 the only possibility for an admissible config is that adjacent to a face with 3 values equal to 0 has such vertex;
533 v0,v1 are reused */
534 if ( !res && nzeros == 2 && nsame == 1 ) {
535 for (j=0; j<3; j++) {
536 i0 = MMG5_idir[i][j];
537 v0 = sol->m[pt->v[i0]];
538 if ( v0 != 0.0 && MG_SMSGN(v,v0) ) break;
539 }
540
541 adja = &mesh->adja[4*(iel-1)+1];
542 jel = adja[i0] / 4;
543 j0 = adja[i0] % 4;
544 pt1 = &mesh->tetra[jel];
545 v1 = sol->m[pt1->v[j0]];
546 if ( v1 != 0.0 && !MG_SMSGN(v,v1) ) {
547 for (j=0; j<4; j++)
548 if ( pt1->v[j] == np ) break;
549 res = 4*jel+j;
550 }
551 }
552
553 if ( ( nzeros == 2 && nsame == 1 ) || ( nsame >= 1 && nopp >= 1 ) ) {
554 bdy[ibdy] = list[l];
555 ibdy++;
556 }
557 }
558
559 /* Invalid configuration has been created */
560 if ( !res )
561 return 0;
562
563 /* Reset the current part of the ball, and start back the process with the other sign */
564 iel = res / 4;
565 pt = &mesh->tetra[iel];
566 base = ++mesh->base;
567 pt->flag = base;
568
569 memset(list,0,(MMG3D_LMAX+1)*sizeof(MMG5_int));
570 ilist = cur = 0;
571 list[ilist] = res;
572 ilist++;
573 while ( cur < ilist ) {
574 iel = list[cur] / 4;
575 i = list[cur] % 4;
576 pt = &mesh->tetra[iel];
577 adja = &mesh->adja[4*(iel-1)+1];
578
579 /* Pile up faces sharing a vertex with opposite sign to v */
580 for (j=0; j<3; j++) {
581 i1 = MMG5_idir[i][MMG5_inxt2[j]];
582 i2 = MMG5_idir[i][MMG5_iprv2[j]];
583 v1 = sol->m[pt->v[i1]];
584 v2 = sol->m[pt->v[i2]];
585
586 if ( v1 == 0.0 && v2 == 0.0 ) {
587 jel = adja[MMG5_idir[i][j]];
588 if( !jel ) continue;
589 jel /=4 ;
590 pt1 = &mesh->tetra[jel];
591 pt1->flag = base;
592 }
593
594 else if ( ( ( v1 != 0.0 ) && (!MG_SMSGN(v,v1)) ) || ( ( v2 != 0.0 ) && (!MG_SMSGN(v,v2)) ) ) {
595 jel = adja[MMG5_idir[i][j]];
596 if( !jel ) continue;
597 jel /= 4;
598 pt1 = &mesh->tetra[jel];
599
600 j0 = MMG5_idir[i][0];
601 j1 = MMG5_idir[i][1];
602 j2 = MMG5_idir[i][2];
603
604 v0 = sol->m[pt1->v[j0]];
605 v1 = sol->m[pt1->v[j1]];
606 v2 = sol->m[pt1->v[j2]];
607
608 nzeros = nsame = nopp = 0;
609
610 if ( v0 == 0.0 )
611 nzeros++;
612 else if ( MG_SMSGN(v,v0) )
613 nsame++;
614 else
615 nopp++;
616
617 if ( v1 == 0.0 )
618 nzeros++;
619 else if ( MG_SMSGN(v,v1) )
620 nsame++;
621 else
622 nopp++;
623
624 if ( v2 == 0.0 )
625 nzeros++;
626 else if ( MG_SMSGN(v,v2) )
627 nsame++;
628 else
629 nopp++;
630
631 if ( ( nzeros == 2 && nsame == 1 ) || ( nsame >= 1 && nopp >= 1 ) ) {
632 if ( pt1->flag < base - 1 ) return 0;
633 }
634
635 if ( pt1->flag == base ) continue;
636 for (ip=0; ip<4; ip++) {
637 if ( pt1->v[ip] == np ) break;
638 }
639 assert( ip < 4 );
640 pt1->flag = base;
641 list[ilist] = 4*jel + ip;
642 ilist++;
643 assert(ilist < MMG3D_LMAX);
644 }
645 }
646 cur++;
647 }
648
649 /* Now, all elements of bdy should have been marked by a flag base + 1 */
650 for (l=0; l<ibdy; l++) {
651 iel = bdy[l] / 4;
652 pt = &mesh->tetra[iel];
653 if ( pt->flag != base ) return 0;
654 }
655
656 return 1;
657}
658
669 MMG5_pTetra pt;
670 MMG5_pPoint p0;
671 double *tmp;
672 MMG5_int k,nc,ns,ip,ncg;
673 int8_t i;
674
675 /* create tetra adjacency */
676 if ( !MMG3D_hashTetra(mesh,1) ) {
677 fprintf(stderr,"\n ## Error: %s: hashing problem (1). Exit program.\n",
678 __func__);
679 return 0;
680 }
681
682 /* Reset point flags */
683 for (k=1; k<=mesh->np; k++)
684 mesh->point[k].flag = 0;
685
686 MMG5_ADD_MEM(mesh,(mesh->npmax+1)*sizeof(double),"temporary table",
687 fprintf(stderr," Exit program.\n");
688 return 0);
689 MMG5_SAFE_CALLOC(tmp,mesh->npmax+1,double,return 0);
690
691 /* Include tetras with very poor quality that are connected to the negative part */
692 for (k=1; k<=mesh->ne; k++) {
693 pt = &mesh->tetra[k];
694 if ( !pt->v[0] ) continue;
695 if ( pt->qual < MMG5_EPS ) {
696 for (i=0; i<4; i++) {
697 ip = pt->v[i];
698 if ( sol->m[ip] < 1000.0*MMG5_EPS ) break;
699 }
700 if ( i < 4 ) {
701 for (i=0; i<4; i++) {
702 ip = pt->v[i];
703 sol->m[ip] = -1000.0*MMG5_EPS;
704 }
705 }
706 }
707 }
708
709 /* Snap values of sol that are close to 0 to 0 exactly */
710 ns = 0;
711 for (k=1; k<=mesh->np; k++) {
712 p0 = &mesh->point[k];
713 if ( !MG_VOK(p0) ) continue;
714 if ( fabs(sol->m[k]) < MMG5_EPS ) {
715 if ( mesh->info.ddebug )
716 fprintf(stderr," ## Warning: %s: snapping value at vertex %" MMG5_PRId "; "
717 "previous value: %E.\n",__func__,k,fabs(sol->m[k]));
718
719 tmp[k] = ( fabs(sol->m[k]) < MMG5_EPSD ) ?
720 (-100.0*MMG5_EPS) : sol->m[k];
721 p0->flag = 1;
722 sol->m[k] = 0;
723 ns++;
724 }
725 }
726
727 ncg = 0;
728 do {
729 nc = 0;
730 /* Check snapping did not lead to a nonmanifold situation */
731 for (k=1; k<=mesh->ne; k++) {
732 pt = &mesh->tetra[k];
733 if ( !MG_EOK(pt) ) continue;
734 for (i=0; i<4; i++) {
735 ip = pt->v[i];
736 p0 = &mesh->point[ip];
737 if ( p0->flag == 1 ) {
738 if ( !MMG3D_ismaniball(mesh,sol,k,i) ) {
739 if ( tmp[ip] < 0.0 )
740 sol->m[ip] = -100.0*MMG5_EPS;
741 else
742 sol->m[ip] = +100.0*MMG5_EPS;
743
744 p0->flag = 0;
745 nc++;
746 }
747 }
748 }
749 }
750 ncg += nc;
751 }
752 while ( nc );
753
754 if ( (abs(mesh->info.imprim) > 5 || mesh->info.ddebug) && ns+ncg > 0 )
755 fprintf(stdout," %8" MMG5_PRId " points snapped, %" MMG5_PRId " corrected\n",ns,ncg);
756
757 /* Reset point flags */
758 for (k=1; k<=mesh->np; k++)
759 mesh->point[k].flag = 0;
760
761 /* memory free */
764
765 return 1;
766}
767
779 MMG5_pTetra pt,pt1,pt2;
780 MMG5_pxTetra pxt;
781 double volc,voltot,v0,v1,v2,v3;
782 int l,cur,ipile;
783 MMG5_int ncp,ncm,base,k,kk,ll,ip0,ip1,ip2,ip3,*adja,*pile;
784 int8_t i,j,i1,onbr;
785
786 ncp = 0;
787 ncm = 0;
788
789 /* Erase tetra flags */
790 for (k=1; k<=mesh->ne; k++) mesh->tetra[k].flag = 0;
791
792 /* Calculate volume of the total mesh (x6 to avoid useless division)*/
793 voltot = 0.0;
794 for (k=1; k<=mesh->ne; k++) {
795 pt = &mesh->tetra[k];
796 if ( !MG_EOK(pt) ) continue;
797 voltot += fabs ( MMG5_orvol(mesh->point,pt->v) );
798 }
799
800 /* Memory allocation for pile */
801 MMG5_ADD_MEM(mesh,(mesh->ne+1)*sizeof(MMG5_int),"temporary table",
802 printf(" Exit program.\n");
803 return 0);
804 MMG5_SAFE_CALLOC(pile,mesh->ne+1,MMG5_int,return 0);
805
806 /* Investigate only positive connected components */
807 base = ++mesh->base;
808
809 for (k=1; k<=mesh->ne; k++) {
810 ipile = 0;
811 volc = 0.0;
812 pt = &mesh->tetra[k];
813 if ( !MG_EOK(pt) ) continue;
814 if ( pt->flag == base ) continue;
815
816 /* Checks signs of the LS function at the 4 vertices of pt */
817 ip0 = pt->v[0];
818 ip1 = pt->v[1];
819 ip2 = pt->v[2];
820 ip3 = pt->v[3];
821
822 v0 = sol->m[ip0];
823 v1 = sol->m[ip1];
824 v2 = sol->m[ip2];
825 v3 = sol->m[ip3];
826
827 if ( v0 <= 0.0 && v1 <= 0.0 && v2 <= 0.0 && v3 <= 0.0 ) continue;
828
829 /* Add tetra to pile if one vertex is > 0 */
830 pt->flag = base;
831 pile[ipile] = k;
832 ipile++;
833 if ( ipile > mesh->ne ) {
834 fprintf(stderr,"\n ## Problem in length of pile; function rmc.\n"
835 " Check that the level-set intersect the mesh.\n"
836 " Exit program.\n");
837
838 return 0;
839 }
840
841 /* Pile up all the positive connected component attached to the first tetra */
842 cur = 0;
843 do {
844 kk = pile[cur];
845 pt1 = &mesh->tetra[kk];
846
847 /* Add local volume fraction of the positive subdomain to volc */
848 volc += MMG3D_vfrac(mesh,sol,kk,1);
849
850 /* Add adjacent tetra to kk via positive vertices to the pile, if need be */
851 adja = &mesh->adja[4*(kk-1)+1];
852 for (i=0; i<4; i++) {
853 ip0 = pt1->v[i];
854 if ( sol->m[ip0] <= 0.0 ) continue;
855
856 for ( i1=0; i1<3; ++i1 ) {
857 ll = adja[MMG5_idir[i][i1]] / 4;
858 if ( !ll ) continue;
859
860 pt2 = &mesh->tetra[ll];
861 if ( MG_EOK(pt2) && pt2->flag != base ) {
862 pt2->flag = base;
863 pile[ipile] = ll;
864 ipile++;
865 if ( ipile > mesh->ne ) {
866 fprintf(stderr,"\n ## Problem in length of pile; function rmc. Exit program.\n");
867 return 0;
868 }
869 }
870 }
871 }
872 }
873 while ( ++cur < ipile );
874
875 /* Remove connected component if its volume is too small */
876 if ( volc < mesh->info.rmc * voltot ) {
877 for (l=0; l<ipile; l++) {
878 pt1 = &mesh->tetra[pile[l]];
879 for (i=0; i<4; i++) {
880 ip0 = pt1->v[i];
881 if ( sol->m[ip0] > 0.0 ) {
882 sol->m[ip0] = - 100*MMG5_EPS;
883 }
884 }
885 }
886 ncp++;
887 }
888 }
889
890 /* Investigate only negative connected components */
891 base = ++mesh->base;
892
893 for (k=1; k<=mesh->ne; k++) {
894 ipile = 0;
895 volc = 0.0;
896 pt = &mesh->tetra[k];
897 if ( !MG_EOK(pt) ) continue;
898 if ( pt->flag == base ) continue;
899
900 /* Checks signs of the LS function at the 4 vertices of pt */
901 ip0 = pt->v[0];
902 ip1 = pt->v[1];
903 ip2 = pt->v[2];
904 ip3 = pt->v[3];
905
906 v0 = sol->m[ip0];
907 v1 = sol->m[ip1];
908 v2 = sol->m[ip2];
909 v3 = sol->m[ip3];
910
911 if ( v0 >= 0.0 && v1 >= 0.0 && v2 >= 0.0 && v3 >= 0.0 ) continue;
912
913 /* Add tetra to pile if one vertex is > 0 */
914 pt->flag = base;
915 pile[ipile] = k;
916 ipile++;
917 if ( ipile > mesh->ne ) {
918 fprintf(stderr,"\n ## Problem in length of pile; function rmc. Exit program.\n");
919 return 0;
920 }
921
922 /* Pile up all the negative connected component attached to the first tetra */
923 cur = 0;
924 do {
925 kk = pile[cur];
926 pt1 = &mesh->tetra[kk];
927
928 /* Add local volume fraction of the negative subdomain to volc */
929 volc += MMG3D_vfrac(mesh,sol,kk,-1);
930
931 /* Add adjacent tetra to kk via negative vertices to the pile, if need be */
932 adja = &mesh->adja[4*(kk-1)+1];
933 for (i=0; i<4; i++) {
934 ip0 = pt1->v[i];
935 if ( sol->m[ip0] >= 0.0 ) continue;
936
937 for ( i1=0; i1<3; ++i1 ) {
938 ll = adja[MMG5_idir[i][i1]] / 4;
939 if ( !ll ) continue;
940
941 pt2 = &mesh->tetra[ll];
942 if ( MG_EOK(pt2) && pt2->flag != base ) {
943 pt2->flag = base;
944 pile[ipile] = ll;
945 ipile++;
946 if ( ipile > mesh->ne ) {
947 fprintf(stderr,"\n ## Problem in length of pile; function rmc. Exit program.\n");
948 return 0;
949 }
950 }
951 }
952 }
953 }
954 while ( ++cur < ipile );
955
956 /* Remove connected component if its volume is too small */
957 if ( volc < mesh->info.rmc * voltot ) {
958 for (l=0; l<ipile; l++) {
959 pt1 = &mesh->tetra[pile[l]];
960 for (i=0; i<4; i++) {
961 ip0 = pt1->v[i];
962 if ( sol->m[ip0] < 0.0 ) sol->m[ip0] = 100*MMG5_EPS;
963 }
964 }
965 ncm++;
966 }
967
968 /* Remove connected component if it is not attached to one base reference */
969 if ( mesh->info.nbr ) {
970 onbr = 0;
971 for (l=0; l<ipile; l++) {
972 pt1 = &mesh->tetra[pile[l]];
973 if ( pt1->xt ) {
974 pxt = &mesh->xtetra[pt1->xt];
975 for (i=0; i<4; i++) {
976 if ( MMG5_isbr(mesh,pxt->ref[i]) ) {
977 for (j=0; j<3; j++) {
978 ip0 = pt1->v[MMG5_idir[i][j]];
979 if ( sol->m[ip0] < 0.0 ) {
980 onbr = 1;
981 break;
982 }
983 }
984 }
985 }
986 }
987 if ( onbr ) break;
988 }
989
990 if ( !onbr ) {
991 for (l=0; l<ipile; l++) {
992 pt1 = &mesh->tetra[pile[l]];
993 for (i=0; i<4; i++) {
994 ip0 = pt1->v[i];
995 if ( sol->m[ip0] < 0.0 ) sol->m[ip0] = 100*MMG5_EPS;
996 }
997 }
998 ncm++;
999 }
1000 }
1001 }
1002
1003 /* Erase tetra flags */
1004 for (k=1; k<=mesh->ne; k++) mesh->tetra[k].flag = 0;
1005
1006 /* Release memory */
1007 MMG5_DEL_MEM(mesh,pile);
1008
1009 if ( mesh->info.imprim > 0 || mesh->info.ddebug ) {
1010 printf("\n *** Removed %" MMG5_PRId " positive parasitic bubbles and %" MMG5_PRId " negative parasitic bubbles\n",ncp,ncm);
1011 }
1012
1013 return 1;
1014}
1015
1027 MMG5_pTetra pt;
1028 MMG5_pxTetra pxt;
1029 MMG5_pPoint p0,p1;
1030 MMG5_Hash hash;
1031 double c[3],v0,v1,s;
1032 int ier;
1033 MMG5_int vx[6],k,ip0,ip1,np,nb,ns,ne,src,refext,refint;
1034 int8_t ia,j,npneg;
1035 static int8_t mmgWarn = 0;
1036
1037 /* reset point flags and h */
1038 for (k=1; k<=mesh->np; k++)
1039 mesh->point[k].flag = 0;
1040
1041 /* compute the number nb of intersection points on edges */
1042 nb = 0;
1043 for (k=1; k<=mesh->ne; k++) {
1044 pt = &mesh->tetra[k];
1045 for (ia=0; ia<6; ia++) {
1046 ip0 = pt->v[MMG5_iare[ia][0]];
1047 ip1 = pt->v[MMG5_iare[ia][1]];
1048 p0 = &mesh->point[ip0];
1049 p1 = &mesh->point[ip1];
1050 if ( p0->flag && p1->flag ) continue;
1051 v0 = sol->m[ip0];
1052 v1 = sol->m[ip1];
1053 if ( fabs(v0) > MMG5_EPSD2 && fabs(v1) > MMG5_EPSD2 && v0*v1 < 0.0 ) {
1054 if ( !p0->flag ) {
1055 p0->flag = ++nb;
1056 }
1057 if ( !p1->flag ) {
1058 p1->flag = ++nb;
1059 }
1060 }
1061 }
1062 }
1063 if ( ! nb ) return 1;
1064
1065 /* Create intersection points at 0 isovalue and set flags to tetras */
1066 if ( !MMG5_hashNew(mesh,&hash,nb,7*nb) ) return 0;
1067 /* Hash all boundary and required edges, and put ip = -1 in hash structure */
1068 for (k=1; k<=mesh->ne; k++) {
1069 pt = &mesh->tetra[k];
1070 if ( !MG_EOK(pt) ) continue;
1071
1072 /* avoid split of edges belonging to a required tet */
1073 if ( pt->tag & MG_REQ ) {
1074 for (ia=0; ia<6; ia++) {
1075 ip0 = pt->v[MMG5_iare[ia][0]];
1076 ip1 = pt->v[MMG5_iare[ia][1]];
1077 np = -1;
1078 if ( !MMG5_hashEdge(mesh,&hash,ip0,ip1,np) ) return -1;
1079 }
1080 continue;
1081 }
1082
1083 if ( !pt->xt ) continue;
1084
1085 pxt = &mesh->xtetra[pt->xt];
1086 for (ia=0; ia<4; ia++) {
1087 if ( !(pxt->ftag[ia] & MG_BDY) ) continue;
1088
1089 for (j=0; j<3; j++) {
1090 if ( !(pxt->tag[ MMG5_iarf[ia][j] ] & MG_REQ) ) continue;
1091
1092 ip0 = pt->v[MMG5_idir[ia][MMG5_inxt2[j]]];
1093 ip1 = pt->v[MMG5_idir[ia][MMG5_iprv2[j]]];
1094 np = -1;
1095 if ( !MMG5_hashEdge(mesh,&hash,ip0,ip1,np) ) return -1;
1096 }
1097 }
1098 }
1099
1100
1101 for (k=1; k<=mesh->ne; k++) {
1102 pt = &mesh->tetra[k];
1103 if ( !MG_EOK(pt) ) continue;
1104
1105 for (ia=0; ia<6; ia++) {
1106 ip0 = pt->v[MMG5_iare[ia][0]];
1107 ip1 = pt->v[MMG5_iare[ia][1]];
1108 np = MMG5_hashGet(&hash,ip0,ip1);
1109
1110 if ( np>0 ) continue;
1111
1112 if ( !MMG5_isSplit(mesh,pt->ref,&refint,&refext) ) continue;
1113
1114 p0 = &mesh->point[ip0];
1115 p1 = &mesh->point[ip1];
1116 v0 = sol->m[ip0];
1117 v1 = sol->m[ip1];
1118 if ( fabs(v0) < MMG5_EPSD2 || fabs(v1) < MMG5_EPSD2 ) continue;
1119 else if ( MG_SMSGN(v0,v1) ) continue;
1120 else if ( !p0->flag || !p1->flag ) continue;
1121
1122 npneg = (np<0);
1123
1124 s = v0 / (v0-v1);
1125
1126 s = MG_MAX(MG_MIN(s,1.0-MMG5_EPS),MMG5_EPS);
1127 c[0] = p0->c[0] + s*(p1->c[0]-p0->c[0]);
1128 c[1] = p0->c[1] + s*(p1->c[1]-p0->c[1]);
1129 c[2] = p0->c[2] + s*(p1->c[2]-p0->c[2]);
1130
1131#ifdef USE_POINTMAP
1132 src = p0->src;
1133#else
1134 src = 1;
1135#endif
1136 np = MMG3D_newPt(mesh,c,0,src);
1137 if ( !np ) {
1138 MMG5_int oldnpmax = mesh->npmax;
1140 fprintf(stderr,"\n ## Error: %s: unable to"
1141 " allocate a new point\n",__func__);
1143 return 0
1144 ,c,0,src);
1145 if( met ) {
1146 if( met->m ) {
1147 MMG5_ADD_MEM(mesh,(met->size*(mesh->npmax-met->npmax))*sizeof(double),
1148 "larger solution",
1150 mesh->memCur -= (mesh->npmax - oldnpmax)*sizeof(MMG5_Point);
1151 mesh->npmax = oldnpmax;
1152 mesh->np = mesh->npmax-1;
1153 mesh->npnil = 0;
1154 return 0);
1155 MMG5_SAFE_REALLOC(met->m,met->size*(met->npmax+1),
1156 met->size*(mesh->npmax+1),
1157 double,"larger solution",
1159 mesh->memCur -= (mesh->npmax - oldnpmax)*sizeof(MMG5_Point);
1160 mesh->npmax = oldnpmax;
1161 mesh->np = mesh->npmax-1;
1162 mesh->npnil = 0;
1163 return 0);
1164 }
1165 met->npmax = mesh->npmax;
1166 }
1167 }
1168 sol->m[np] = 0;
1169 /* If user provide a metric, interpolate it at the new point */
1170 if ( met && met->m ) {
1171 if ( met->size > 1 ) {
1172 ier = MMG3D_intmet33_ani(mesh,met,k,ia,np,s);
1173 }
1174 else {
1175 ier = MMG5_intmet_iso(mesh,met,k,ia,np,s);
1176 }
1177 if ( ier <= 0 ) {
1178 // Unable to compute the metric
1179 fprintf(stderr,"\n ## Error: %s: unable to"
1180 " interpolate the metric during the level-set"
1181 " discretization\n",__func__);
1182 return 0;
1183 }
1184 }
1185
1186 if ( npneg ) {
1187 /* We split a required edge */
1188 if ( !mmgWarn ) {
1189 mmgWarn = 1;
1190 fprintf(stderr," ## Warning: %s: the level-set intersect at least"
1191 " one required entity. Required entity ignored.\n\n",__func__);
1192 }
1193 MMG5_hashUpdate(&hash,ip0,ip1,np);
1194 }
1195 else
1196 MMG5_hashEdge(mesh,&hash,ip0,ip1,np);
1197 }
1198 }
1199
1200 /* Proceed to splitting, according to flags to tets */
1201 ne = mesh->ne;
1202 ns = 0;
1203 ier = 1;
1204 for (k=1; k<=ne; k++) {
1205 pt = &mesh->tetra[k];
1206 if ( !MG_EOK(pt) ) continue;
1207 pt->flag = 0;
1208 memset(vx,0,6*sizeof(MMG5_int));
1209 for (ia=0; ia<6; ia++) {
1210 vx[ia] = MMG5_hashGet(&hash,pt->v[MMG5_iare[ia][0]],pt->v[MMG5_iare[ia][1]]);
1211 if ( vx[ia] > 0 ) MG_SET(pt->flag,ia);
1212 }
1213 switch (pt->flag) {
1214 case 1: case 2: case 4: case 8: case 16: case 32: /* 1 edge split */
1215 ier = MMG5_split1(mesh,met,k,vx,1);
1216 ns++;
1217 break;
1218
1219 case 48: case 24: case 40: case 6: case 34: case 36:
1220 case 20: case 5: case 17: case 9: case 3: case 10: /* 2 edges (same face) split */
1221 ier = MMG5_split2sf(mesh,met,k,vx,1);
1222 ns++;
1223 break;
1224
1225 case 7: case 25: case 42: case 52: /* 3 edges on conic configuration splitted */
1226 ier = MMG5_split3cone(mesh,met,k,vx,1);
1227 ns++;
1228 break;
1229
1230 case 30: case 45: case 51:
1231 ier = MMG5_split4op(mesh,met,k,vx,1);
1232 ns++;
1233 break;
1234
1235 default :
1236 assert(pt->flag == 0);
1237 break;
1238 }
1239 if ( !ier ) return 0;
1240 }
1241 if ( (mesh->info.ddebug || abs(mesh->info.imprim) > 5) && ns > 0 )
1242 fprintf(stdout," %7" MMG5_PRId " splitted\n",ns);
1243
1244 MMG5_DEL_MEM(mesh,hash.item);
1245 return ns;
1246}
1247
1248
1258 MMG5_pTetra pt;
1259 double v;
1260 int ier;
1261 MMG5_int ref,refint,refext,k,ip;
1262 int8_t nmns,npls,nz,i;
1263
1264 for (k=1; k<=mesh->ne; k++) {
1265 pt = &mesh->tetra[k];
1266 if ( !MG_EOK(pt) ) continue;
1267
1268 ref = pt->ref;
1269
1270 nmns = npls = nz = 0;
1271 for (i=0; i<4; i++) {
1272 ip = pt->v[i];
1273 v = sol->m[ip];
1274 if ( v > 0.0 )
1275 npls++;
1276 else if ( v < 0.0 )
1277 nmns++;
1278 else
1279 nz ++;
1280 }
1281 /* Remark: this test is not consistent with the test of the lssurf option
1282 * because it autorizes the level-set to be superposed with the surface */
1283 assert(nz < 4);
1284 ier = MMG5_isSplit(mesh,ref,&refint,&refext);
1285
1286 if ( npls ) {
1287 if ( ier ) {
1288 assert(!nmns);
1289 pt->ref = refext;
1290 }
1291 }
1292 else {
1293 if ( ier ) {
1294 assert(nmns);
1295 pt->ref = refint;
1296 }
1297 }
1298 }
1299 return 1;
1300}
1301
1311 MMG5_pTetra pt,pt1,ptmax,ptmin;
1312 MMG5_pxTetra pxt;
1313 int i,j,imax,imin;
1314 MMG5_int *adja,k,jel;
1315
1316 if ( (!mesh->info.iso) || (!mesh->info.opnbdy) ) {
1317 /* In non opnbdy mode, info stored in xtetra is not used */
1318 /* In non ls mode, xtetra are alread updated */
1319 return 1;
1320 }
1321
1322 /* Opnbdy mode uses data stored in xtetra but in iso mode, the new triangles
1323 * created by the ls discretization haven't been stored inside the xtetra */
1324 if ( !mesh->xtetra ) {
1325 fprintf(stderr,"\n ## Error: %s: the xtetra array must be allocated.\n",
1326 __func__);
1327 return 0;
1328 }
1329 if ( !mesh->adja ) {
1330 fprintf(stderr,"\n ## Error: %s: the ajda array must be allocated.\n",
1331 __func__);
1332 return 0;
1333 }
1334
1335
1336 for (k=1; k<=mesh->ne; k++) {
1337 pt = &mesh->tetra[k];
1338
1339 adja = &mesh->adja[4*(k-1)+1];
1340
1341 for (i=0; i<4; i++) {
1342 if ( !adja[i] ) {
1343 /* Face is already stored */
1344 continue;
1345 }
1346
1347 jel = adja[i]/4;
1348 pt1 = &mesh->tetra[jel];
1349
1350 if ( pt->ref == pt1->ref ) {
1351 /* Potential opnbdy face is already stored */
1352 continue;
1353 }
1354
1355 j = adja[i]%4;
1356 /* Detection of the tetra of higher ref */
1357 if ( pt->ref > pt1->ref ) {
1358 ptmax = pt;
1359 imax = i;
1360 ptmin = pt1;
1361 imin = j;
1362 }
1363 else {
1364 ptmax = pt1;
1365 imax = j;
1366 ptmin = pt;
1367 imin = i;
1368 }
1369
1370 /* Update the xtetra array for both tetra */
1371 /* Tetra ptmax */
1372 if ( !ptmax->xt ) {
1373 mesh->xt++;
1374 if ( mesh->xt > mesh->xtmax ) {
1376 "larger xtetra table",
1377 mesh->xt--;
1378 fprintf(stderr," Exit program.\n");return 0;);
1379 }
1380 ptmax->xt = mesh->xt;
1381 }
1382
1383 pxt = &mesh->xtetra[ptmax->xt];
1384 pxt->ref[imax] = mesh->info.isoref;
1385 pxt->ftag[imax] |= MG_BDY;
1386 MG_SET(pxt->ori,imax);
1387
1388 /* Tetra ptmin */
1389 if ( !ptmin->xt ) {
1390 mesh->xt++;
1391 if ( mesh->xt > mesh->xtmax ) {
1393 "larger xtetra table",
1394 mesh->xt--;
1395 fprintf(stderr," Exit program.\n");return 0;);
1396 }
1397 ptmin->xt = mesh->xt;
1398 }
1399
1400 pxt = &mesh->xtetra[ptmin->xt];
1401 pxt->ref[imin] = mesh->info.isoref;
1402 pxt->ftag[imin] |= MG_BDY;
1403 MG_CLR(pxt->ori,imin);
1404 }
1405 }
1406 return 1;
1407}
1408
1420int MMG3D_chkmaniball(MMG5_pMesh mesh, MMG5_int start, int8_t ip){
1421 MMG5_pTetra pt,pt1;
1422 int ilist,cur,nref;
1423 MMG5_int base,ref,*adja,list[MMG3D_LMAX+2],k,k1,nump;
1424 int8_t i,l,j;
1425
1426 base = ++mesh->base;
1427 ilist = 0;
1428
1429 pt = &mesh->tetra[start];
1430 nump = pt->v[ip];
1431 ref = pt->ref;
1432
1433 /* Store initial tetrahedron */
1434 pt->flag = base;
1435 list[ilist] = 4*start+ip;
1436 ilist++;
1437
1438 /* explore list, and find all tets in ball of p belonging to the component ref */
1439 cur = 0;
1440 while( cur < ilist ) {
1441 k = list[cur] / 4;
1442 i = list[cur] % 4;
1443
1444 adja = &mesh->adja[4*(k-1)+1];
1445 for(l=0; l<3; l++){
1446 i = MMG5_inxt3[i];
1447
1448 /* Travel only through non boundary faces. */
1449 k1 = adja[i];
1450 if(!k1) continue;
1451 k1 /= 4;
1452 pt1 = &mesh->tetra[k1];
1453 if( MMG5_isNotSplit(mesh,pt1->ref) ) continue;
1454
1455 if( pt1->ref != ref ) continue;
1456
1457 if( pt1->flag == base ) continue;
1458 pt1->flag = base;
1459
1460 for(j=0; j<4 ; j++){
1461 if(pt1->v[j] == nump)
1462 break;
1463 }
1464 assert(j<4);
1465
1466 /* overflow */
1467 assert ( ilist <= MMG3D_LMAX-3 );
1468 list[ilist] = 4*k1+j;
1469 ilist++;
1470 }
1471 cur++;
1472 }
1473
1474 /* Number of caught tets with ref ptstart->ref*/
1475 nref = ilist;
1476
1477 /* Complete ball of point */
1478 cur = 0;
1479 while(cur < ilist){
1480 k = list[cur] / 4;
1481 i = list[cur] % 4;
1482
1483 adja = &mesh->adja[4*(k-1)+1];
1484 for(l=0; l<3; l++){
1485 i = MMG5_inxt3[i];
1486
1487 k1 = adja[i];
1488 if ( !k1 ) continue;
1489 k1/=4;
1490
1491 pt1 = &mesh->tetra[k1];
1492 if( MMG5_isNotSplit(mesh,pt1->ref) ) continue;
1493
1494 if(pt1->flag == base) continue;
1495 pt1->flag = base;
1496
1497 for(j=0; j<4 ; j++){
1498 if(pt1->v[j] == nump)
1499 break;
1500 }
1501 assert(j<4);
1502
1503 /* overflow */
1504 assert ( ilist <= MMG3D_LMAX-3 );
1505 list[ilist] = 4*k1+j;
1506 ilist++;
1507 }
1508 cur++;
1509 }
1510
1511 /* Elements from nref to ilist-1 must not have ref ptstart->ref */
1512 for(cur=nref; cur<ilist; cur++) {
1513 k = list[cur] / 4;
1514 pt = &mesh->tetra[k];
1515 if( pt->ref == ref ) {
1516 fprintf(stderr," *** Topological problem\n");
1517 fprintf(stderr," non manifold surface at point %" MMG5_PRId " %" MMG5_PRId "\n",nump, MMG3D_indPt(mesh,nump));
1518 fprintf(stderr," non manifold surface at tet %" MMG5_PRId " (ip %d)\n", MMG3D_indElt(mesh,start),ip);
1519 fprintf(stderr," nref (color %d) %" MMG5_PRId "\n",nref,ref);
1520 return 0;
1521 }
1522 }
1523
1524 return 1;
1525}
1526
1529 MMG5_pTetra pt,pt1;
1530 MMG5_int ref;
1531 MMG5_int iel,k,*adja;
1532 int8_t i,j,ip,cnt;
1533 static int8_t mmgWarn0 = 0;
1534
1535 for(k=1; k<=mesh->np; k++){
1536 mesh->point[k].flag = 0;
1537 }
1538
1540 for(k=1; k<=mesh->ne; k++) {
1541 pt = &mesh->tetra[k];
1542 if ( !MG_EOK(pt) ) continue;
1543 adja = &mesh->adja[4*(k-1)+1];
1544
1545 ref = pt->ref;
1546 cnt = 0;
1547 for(i=0; i<4; i++) {
1548 if( !adja[i] ) {
1549 cnt++;
1550 }
1551 else {
1552 pt1 = &mesh->tetra[adja[i]/4];
1553 if ( pt1->ref != ref ) cnt++;
1554 }
1555 }
1556 if ( cnt == 4 ) {
1557 if ( !mmgWarn0 ) {
1558 mmgWarn0 = 1;
1559 fprintf(stderr,"\n ## Warning: %s: at least 1 tetra with 4 boundary"
1560 " faces.\n",__func__);
1561 }
1562 //return 0;
1563 }
1564 }
1565
1567 for(k=1; k<=mesh->ne; k++){
1568 pt = &mesh->tetra[k];
1569 if ( !MG_EOK(pt) || (pt->tag & MG_REQ)) continue;
1570 adja = &mesh->adja[4*(k-1)+1];
1571
1572 for(i=0; i<4; i++){
1573 if(!adja[i]) continue;
1574 iel = adja[i] / 4;
1575 pt1 = &mesh->tetra[iel];
1576 if( !MMG5_isLevelSet(mesh,pt1->ref,pt->ref) ) continue;
1577
1578 for(j=0; j<3; j++){
1579 ip = MMG5_idir[i][j];
1580
1581 /* If the starting point is MG_PARBDY: this is not a non-manifold topology */
1582 /* - True for centralized input in parmmg */
1583 /* - Wrong for distributed input in parmmg: TODO */
1584 if ( !(mesh->point[pt->v[ip]].tag & MG_PARBDY)) {
1585 if(!MMG3D_chkmaniball(mesh,k,ip))
1586 return 0;
1587 }
1588 }
1589 }
1590 }
1591
1592 if ( mesh->info.imprim > 0 || mesh->info.ddebug )
1593 fprintf(stdout," *** Manifold implicit surface.\n");
1594 return 1;
1595}
1596
1608 MMG5_pTetra pt,pt1;
1609 MMG5_int k,iel;
1610 MMG5_int *adja;
1611 int8_t i,j,ip,cnt;
1612
1613 for(k=1; k<=mesh->np; k++){
1614 mesh->point[k].flag = 0;
1615 }
1616
1618 for(k=1; k<=mesh->ne; k++){
1619 pt = &mesh->tetra[k];
1620 if ( !MG_EOK(pt) || (pt->tag & MG_REQ)) continue;
1621
1622 cnt = 0;
1623 for(j=0; j<4; j++) {
1624 if( sol->m[pt->v[j]] == 0.0 ) cnt++;
1625 }
1626 if(cnt == 4) {
1627 fprintf(stderr,"\n ## Error: %s: tetra %" MMG5_PRId ": 4 vertices on implicit boundary.\n",
1628 __func__,k);
1629 return 0;
1630 }
1631 }
1632
1634 for(k=1; k<=mesh->ne; k++){
1635 pt = &mesh->tetra[k];
1636 if ( !MG_EOK(pt) || (pt->tag & MG_REQ)) continue;
1637 adja = &mesh->adja[4*(k-1)+1];
1638
1639 for(i=0; i<4; i++){
1640 if(!adja[i]) continue;
1641 iel = adja[i] / 4;
1642 pt1 = &mesh->tetra[iel];
1643 if(pt1->ref == pt->ref) continue;
1644
1645 for(j=0; j<3; j++){
1646 ip = MMG5_idir[i][j];
1647
1648 /* If the starting point is MG_PARBDY: this is not a non-manifold topology */
1649 /* - True for centralized input in parmmg */
1650 /* - Wrong for distributed input in parmmg: TODO */
1651 if ( !(mesh->point[pt->v[ip]].tag & MG_PARBDY)) {
1652 if(!MMG3D_chkmaniball(mesh,k,ip)){
1653 fprintf(stderr,"\n ## Error: %s: non orientable implicit surface:"
1654 " ball of point %" MMG5_PRId ".\n",__func__,pt->v[ip]);
1655 return 0;
1656 }
1657 }
1658 }
1659 }
1660 }
1661 if ( mesh->info.ddebug ) fprintf(stdout," *** Manifold implicit surface.\n");
1662 return 1;
1663}
1664
1683int MMG3D_chkmanicoll(MMG5_pMesh mesh,MMG5_int k,int iface,int iedg,MMG5_int ndepmin,MMG5_int ndepplus,MMG5_int refmin,MMG5_int refplus,int8_t isminp,int8_t isplp) {
1684 MMG5_pTetra pt,pt1;
1685 int ilist,cur;
1686 MMG5_int stor;
1687 MMG5_int ref,nump,numq,list[MMG3D_LMAX+2],*adja,*adja1,iel,jel,ndepmq,ndeppq,base;
1688 int8_t i,j,ip,jp,iq,jq,voy,indp,indq,isminq,isplq,ismin,ispl;
1689
1690 ilist = 0;
1691 ndepmq = ndeppq = 0;
1692 isplq = isminq = 0;
1693
1694 pt = &mesh->tetra[k];
1695 ip = MMG5_idir[iface][MMG5_inxt2[iedg]];
1696 iq = MMG5_idir[iface][MMG5_iprv2[iedg]];
1697 nump = pt->v[ip];
1698 numq = pt->v[iq];
1699
1700 /* Case when nump does not have any interior (resp. ext.) tetra which will not
1701 disappear : search for start in ball of q */
1702 if ( !ndepmin || !ndepplus ) {
1703 base = ++mesh->base;
1704
1705 pt = &mesh->tetra[k];
1706 for(j=0; j<4; j++) {
1707 if ( pt->v[j] == numq ) break;
1708 }
1709 assert( j < 4 );
1710 list[ilist] = 4*k+j;
1711 ilist++;
1712 assert( ilist < MMG3D_LMAX+2 );
1713 pt->flag = base;
1714
1715 if ( pt->ref == refmin ) isminq = 1;
1716 else if ( pt->ref == refplus ) isplq = 1;
1717
1718 cur = 0;
1719 while( cur < ilist ) {
1720 iel = list[cur] / 4;
1721 i = list[cur] % 4;
1722 adja = &mesh->adja[4*(iel-1)+1];
1723
1724 for (j=0; j<3; j++) {
1725 i = MMG5_inxt3[i];
1726 jel = adja[i];
1727 if ( !jel ) continue;
1728
1729 jel /= 4;
1730 pt1 = &mesh->tetra[jel];
1731
1732 if ( pt1->ref == refmin ) isminq = 1;
1733 else if ( pt1->ref == refplus ) isplq = 1;
1734
1735 if ( pt1->flag == base ) continue;
1736 pt1->flag = base;
1737 for(iq=0; iq<4; iq++)
1738 if ( pt1->v[iq] == numq ) break;
1739 assert( iq < 4 );
1740 /* overflow */
1741 assert ( ilist < MMG3D_LMAX+2 );
1742
1743 list[ilist] = 4*jel+iq;
1744 ilist++;
1745
1746 /* check if jel is an available starting tetra for further enumeration */
1747 if ( !ndeppq && pt1->ref == refplus ) {
1748 for(ip=0; ip<4; ip++)
1749 if ( pt1->v[ip] == nump ) break;
1750 if( ip == 4 ) ndeppq = jel;
1751 }
1752 if( !ndepmq && pt1->ref == refmin ) {
1753 for(ip=0; ip<4; ip++)
1754 if ( pt1->v[ip] == nump ) break;
1755 if( ip == 4 ) ndepmq = jel;
1756 }
1757 }
1758 cur++;
1759 }
1760
1761 memset(list,0,(MMG3D_LMAX+2)*sizeof(MMG5_int));
1762 ilist = 0;
1763 }
1764
1765 ispl = ( isplp || isplq ) ? 1 : 0;
1766 ismin = ( isminp || isminq ) ? 1 : 0;
1767
1771 base = ++mesh->base;
1772
1773 if( ndepmin ) {
1774 pt = &mesh->tetra[ndepmin];
1775 ref = pt->ref;
1776
1777 for(j=0; j<4; j++) {
1778 if ( pt->v[j] == nump ) break;
1779 }
1780 assert( j < 4 );
1781
1782 pt->flag = base;
1783 list[ilist] = - (4*ndepmin+j);
1784 ilist++;
1785 }
1786 else if ( ndepmq ) {
1787 pt = &mesh->tetra[ndepmq];
1788 ref = pt->ref;
1789
1790 for(j=0; j<4; j++) {
1791 if ( pt->v[j] == numq ) break;
1792 }
1793 assert( j < 4 );
1794
1795 pt->flag = base;
1796 list[ilist] = 4*ndepmq+j;
1797 ilist++;
1798 }
1799 else {
1800 if ( ismin && ispl )
1801 return 0;
1802 else
1803 return 1;
1804 }
1805
1806
1807 cur = 0;
1808 while ( cur < ilist ) {
1809 stor = list[cur];
1810 /* Element belongs to the ball of np */
1811 if ( stor <= 0 ) {
1812 stor *= -1;
1813 iel = stor / 4;
1814 ip = stor % 4;
1815
1816 adja = &mesh->adja[4*(iel-1)+1];
1817
1818 jp = ip;
1819 for (i=0; i<3; i++) {
1820 jp = MMG5_inxt3[jp];
1821 jel = adja[jp];
1822 if ( !jel ) continue;
1823
1824 jel /= 4;
1825 voy = adja[jp] % 4;
1826
1827 pt1 = &mesh->tetra[jel];
1828 if ( pt1->ref != ref ) continue;
1829
1830 /* Current tetra is neighbour of a tetra of the shell of (np,nq) */
1831 if( pt1->v[voy] == numq ) {
1832 adja1 = &mesh->adja[4*(jel-1)+1];
1833 for(j=0; j<4; j++)
1834 if (pt1->v[j] == nump ) break;
1835 assert( j< 4);
1836
1837 jel = adja1[j];
1838 if (!jel ) continue;
1839
1840 jel /= 4;
1841 pt1 = &mesh->tetra[jel];
1842
1843 if ( pt1->ref != ref) continue; // ICI, il ne faut pas autoriser à passer si on a à nouveau un tet de la coquille (avant de marquer)
1844 if ( pt1->flag == base ) continue;
1845
1846 /* New tetra to be added must not be itself an element of the shell */
1847 for(j=0; j<4; j++) {
1848 if ( pt1->v[j] == nump ) break;
1849 }
1850 if ( j<4 ) continue;
1851
1852 pt1->flag = base;
1853
1854 for(j=0; j<4; j++)
1855 if ( pt1->v[j] == numq ) break;
1856 assert( j< 4);
1857
1858 list[ilist] = 4*jel+j;
1859 ilist++;
1860 assert( ilist < MMG3D_LMAX+1 );
1861 }
1862 else {
1863 if ( pt1->flag == base ) continue;
1864 pt1->flag = base;
1865 for(j=0; j<4; j++)
1866 if ( pt1->v[j] == nump ) break;
1867 assert( j< 4 );
1868
1869 list[ilist] = - (4*jel+j);
1870 ilist++;
1871 assert( ilist < MMG3D_LMAX+1 );
1872 }
1873 }
1874 }
1875 /* Element belongs to the ball of nq */
1876 else {
1877 iel = stor / 4;
1878 iq = stor % 4;
1879
1880 adja = &mesh->adja[4*(iel-1)+1];
1881
1882 jq = iq;
1883 for (i=0; i<3; i++) {
1884 jq = MMG5_inxt3[jq];
1885 jel = adja[jq];
1886 if ( !jel ) continue;
1887
1888 jel /= 4;
1889 voy = adja[jq] % 4;
1890
1891 pt1 = &mesh->tetra[jel];
1892 if ( pt1->ref != ref ) continue;
1893
1894 /* Current tetra is neighbour of a tetra of the shell of (np,nq) */
1895 if( pt1->v[voy] == nump ) {
1896 adja1 = &mesh->adja[4*(jel-1)+1];
1897 for(j=0; j<4; j++)
1898 if (pt1->v[j] == numq ) break;
1899 assert( j< 4);
1900
1901 jel = adja1[j];
1902 if (!jel ) continue;
1903
1904 jel /= 4;
1905
1906 pt1 = &mesh->tetra[jel];
1907 if ( pt1->ref != ref) continue;
1908 if ( pt1->flag == base ) continue;
1909
1910 /* New tetra to be added must not be itself an element of the shell */
1911 for(j=0; j<4; j++) {
1912 if ( pt1->v[j] == numq ) break;
1913 }
1914 if ( j<4 ) continue;
1915
1916 pt1->flag = base;
1917 for(j=0; j<4; j++)
1918 if (pt1->v[j] == nump ) break;
1919 assert( j< 4);
1920
1921 list[ilist] = -(4*jel+j);
1922 ilist++;
1923 assert( ilist < MMG3D_LMAX+1 );
1924 }
1925 else {
1926 if ( pt1->flag == base ) continue;
1927 pt1->flag = base;
1928 for(j=0; j<4; j++)
1929 if (pt1->v[j] == numq ) break;
1930 assert( j< 4);
1931
1932 list[ilist] = 4*jel+j;
1933 ilist++;
1934 assert( ilist < MMG3D_LMAX+1 );
1935 }
1936 }
1937 }
1938 cur++;
1939 }
1940
1941 assert( cur == ilist );
1942
1944 if( ndepplus ) {
1945 pt = &mesh->tetra[ndepplus];
1946 for(j=0; j<4; j++) {
1947 if ( pt->v[j] == nump ) break;
1948 }
1949 assert( j < 4 );
1950
1951 pt->flag = base;
1952 list[ilist] = - (4*ndepplus+j);
1953 ilist++;
1954 ref = pt->ref;
1955 }
1956 else if ( ndeppq ) {
1957 pt = &mesh->tetra[ndeppq];
1958 for(j=0; j<4; j++) {
1959 if ( pt->v[j] == numq ) break;
1960 }
1961 assert( j < 4 );
1962
1963 pt->flag = base;
1964 list[ilist] = 4*ndeppq+j;
1965 ilist++;
1966 ref = pt->ref;
1967 }
1968 else {
1969 if ( ismin && ispl )
1970 return 0;
1971 else
1972 return 1;
1973 }
1974
1975 while ( cur < ilist ) {
1976 stor = list[cur];
1977 /* Element belongs to the ball of np */
1978 if ( stor <= 0 ) {
1979 stor *= -1;
1980 iel = stor / 4;
1981 ip = stor % 4;
1982
1983 adja = &mesh->adja[4*(iel-1)+1];
1984
1985 jp = ip;
1986
1987 for (i=0; i<3; i++) {
1988 jp = MMG5_inxt3[jp];
1989 jel = adja[jp];
1990
1991 if ( !jel ) continue;
1992
1993 jel /=4;
1994 voy = adja[jp] % 4;
1995
1996 pt1 = &mesh->tetra[jel];
1997 if ( pt1->ref != ref ) continue;
1998
1999 /* Current tetra is neighbour of a tetra of the shell of (np,nq) */
2000 if( pt1->v[voy] == numq ) {
2001 adja1 = &mesh->adja[4*(jel-1)+1];
2002 for(j=0; j<4; j++)
2003 if (pt1->v[j] == nump ) break;
2004 assert( j< 4);
2005
2006 jel = adja1[j];
2007 if (!jel ) continue;
2008
2009 jel /= 4;
2010 pt1 = &mesh->tetra[jel];
2011 if ( pt1->ref != ref) continue;
2012 if ( pt1->flag == base ) continue;
2013
2014 /* New tetra to be added must not be itself an element of the shell */
2015 for(j=0; j<4; j++) {
2016 if ( pt1->v[j] == nump ) break;
2017 }
2018 if ( j<4 ) continue;
2019
2020 pt1->flag = base;
2021 for(j=0; j<4; j++)
2022 if ( pt1->v[j] == numq ) break;
2023 assert( j< 4 );
2024
2025 list[ilist] = 4*jel+j;
2026 ilist++;
2027 assert( ilist < MMG3D_LMAX+1 );
2028 }
2029 else {
2030 if ( pt1->flag == base ) continue;
2031 pt1->flag = base;
2032 for(j=0; j<4; j++)
2033 if (pt1->v[j] == nump ) break;
2034 assert( j< 4);
2035
2036 list[ilist] = - (4*jel+j);
2037 ilist++;
2038 assert( ilist < MMG3D_LMAX+1 );
2039 }
2040 }
2041 }
2042 /* Element belongs to the ball of nq */
2043 else {
2044 iel = stor / 4;
2045 iq = stor % 4;
2046
2047 adja = &mesh->adja[4*(iel-1)+1];
2048
2049 jq = iq;
2050
2051 for (i=0; i<3; i++) {
2052 jq = MMG5_inxt3[jq];
2053 jel = adja[jq];
2054
2055 if ( !jel ) continue;
2056
2057 jel /= 4;
2058 voy = adja[jq] % 4;
2059
2060 pt1 = &mesh->tetra[jel];
2061
2062 if ( pt1->ref != ref ) continue;
2063
2064 /* Current tetra is neighbour of a tetra of the shell of (np,nq) */
2065 if( pt1->v[voy] == nump ) {
2066 adja1 = &mesh->adja[4*(jel-1)+1];
2067 for(j=0; j<4; j++)
2068 if (pt1->v[j] == numq ) break;
2069 assert( j< 4);
2070
2071 jel = adja1[j];
2072 if (!jel ) continue;
2073
2074 jel /= 4;
2075 pt1 = &mesh->tetra[jel];
2076 if ( pt1->ref != ref) continue;
2077 if ( pt1->flag == base ) continue;
2078
2079 /* New tetra to be added must not be itself an element of the shell */
2080 for(j=0; j<4; j++) {
2081 if ( pt1->v[j] == numq ) break;
2082 }
2083 if ( j<4 ) continue;
2084
2085 pt1->flag = base;
2086 for(j=0; j<4; j++)
2087 if (pt1->v[j] == nump ) break;
2088 assert( j< 4);
2089
2090 list[ilist] = -(4*jel+j);
2091 ilist++;
2092 assert( ilist < MMG3D_LMAX+1 );
2093 }
2094 else {
2095 if ( pt1->flag == base ) continue;
2096 pt1->flag = base;
2097 for(j=0; j<4; j++)
2098 if (pt1->v[j] == numq ) break;
2099 assert( j< 4 );
2100
2101 list[ilist] = 4*jel+j;
2102 ilist++;
2103 assert( ilist < MMG3D_LMAX+1 );
2104 }
2105 }
2106 }
2107 cur++;
2108 }
2109 assert( cur == ilist );
2110
2111 /* At this point, all elements of ball np \cup ball nq \setminus shell have been tagged
2112 unless the future ball of nq, ending up from collapse is non manifold */
2113 cur = 0;
2114 while ( cur < ilist ) {
2115 stor = list[cur];
2116
2117 if ( stor <= 0 ) {
2118 stor *= -1;
2119 iel = stor / 4;
2120 ip = stor % 4;
2121 adja = &mesh->adja[4*(iel-1)+1];
2122
2123 jp = ip;
2124 for(i=0; i<3; i++) {
2125 jp = MMG5_inxt3[jp];
2126 jel = adja[jp];
2127
2128 if ( !jel ) continue;
2129
2130 jel /= 4;
2131 pt1 = &mesh->tetra[jel];
2132 if (pt1->flag == base ) continue;
2133 pt1->flag = base;
2134
2135 indp = -1;
2136 indq = -1;
2137 for(j=0; j<4; j++) {
2138 if ( pt1->v[j] == nump )
2139 indp = j;
2140 else if ( pt1->v[j] == numq )
2141 indq = j;
2142 }
2143 assert( indp >= 0 && indp < 4 );
2144
2145 /* Only tets of the shell of (np,nq) can be added, unless future ball is
2146 * non manifold */
2147 if ( indq == -1 ) {
2148 if ( mesh->info.ddebug ) {
2149 fprintf(stderr,"\n ## Warning: %s: we should rarely passed here. "
2150 "tetra %" MMG5_PRId " = %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId ", ref = %" MMG5_PRId ".",__func__,
2151 jel,pt1->v[0],pt1->v[1],pt1->v[2],pt1->v[3],pt1->ref);
2152 }
2153 return 0;
2154 }
2155
2156 list[ilist] = -(4*jel+indp);
2157 ilist++;
2158 assert( ilist < MMG3D_LMAX +1 );
2159 }
2160 }
2161 else {
2162 iel = stor / 4;
2163 iq = stor % 4;
2164 adja = &mesh->adja[4*(iel-1)+1];
2165
2166 jq = iq;
2167 for(i=0; i<3; i++) {
2168 jq = MMG5_inxt3[jq];
2169 jel = adja[jq];
2170
2171 if ( !jel ) continue;
2172
2173 jel /= 4;
2174 pt1 = &mesh->tetra[jel];
2175 if (pt1->flag == base ) continue;
2176 pt1->flag = base;
2177
2178 indp = -1;
2179 indq = -1;
2180
2181 for(j=0; j<4; j++) {
2182 if ( pt1->v[j] == nump )
2183 indp = j;
2184 else if ( pt1->v[j] == numq )
2185 indq = j;
2186 }
2187 assert( indq >= 0 && indq < 4 );
2188
2189 /* Only tets of the shell of (np,nq) can be added, unless future ball is non manifold */
2190 if ( indp == -1 ) {
2191 if ( mesh->info.ddebug ) {
2192 fprintf(stderr,"\n ## Warning: %s: we should rarely passed here. "
2193 "tetra %" MMG5_PRId " = %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId ", ref = %" MMG5_PRId "\n",__func__,
2194 jel,pt1->v[0],pt1->v[1],pt1->v[2],pt1->v[3],pt1->ref);
2195 }
2196 return 0;
2197 }
2198
2199 list[ilist] = 4*jel+indq;
2200 ilist++;
2201 assert( ilist < MMG3D_LMAX +1 );
2202 }
2203 }
2204 cur++;
2205 }
2206
2207 return 1;
2208}
2209
2220 char str[16]="";
2221
2222 /* Set function pointers */
2223 if ( mesh->info.isosurf ) {
2224 strcat(str,"(BOUNDARY PART)");
2225
2226 MMG3D_snpval = MMG3D_snpval_lssurf;
2227 MMG3D_resetRef = MMG3D_resetRef_lssurf;
2228 MMG3D_cuttet = MMG3D_cuttet_lssurf;
2229 MMG3D_setref = MMG3D_setref_lssurf;
2230 }
2231 else {
2232 MMG3D_snpval = MMG3D_snpval_ls;
2233 MMG3D_resetRef = MMG3D_resetRef_ls;
2234 MMG3D_cuttet = MMG3D_cuttet_ls;
2235 MMG3D_setref = MMG3D_setref_ls;
2236 }
2237
2238 if ( abs(mesh->info.imprim) > 3 )
2239 fprintf(stdout," ** ISOSURFACE EXTRACTION %s\n",str);
2240
2241 if ( mesh->nprism || mesh->nquad ) {
2242 fprintf(stderr,"\n ## Error: Isosurface extraction not available with"
2243 " hybrid meshes. Exit program.\n");
2244 return 0;
2245 }
2246
2247 /* Work only with the 0 level set */
2248 MMG5_int k;
2249 for (k=1; k<= sol->np; k++)
2250 sol->m[k] -= mesh->info.ls;
2251
2252 /* Snap values of level set function if need be */
2253 if ( !MMG3D_snpval(mesh,sol) ) {
2254 fprintf(stderr,"\n ## Problem with implicit function. Exit program.\n");
2255 return 0;
2256 }
2257
2258 if ( !MMG3D_hashTetra(mesh,1) ) {
2259 fprintf(stderr,"\n ## Hashing problem. Exit program.\n");
2260 return 0;
2261 }
2262
2263 /* Compatibility triangle orientation w/r tetras */
2264 if ( !MMG5_bdryPerm(mesh) ) {
2265 fprintf(stderr,"\n ## Boundary orientation problem. Exit program.\n");
2266 return 0;
2267 }
2268
2269 if ( !MMG5_chkBdryTria(mesh) ) {
2270 fprintf(stderr,"\n ## Boundary problem. Exit program.\n");
2271 return 0;
2272 }
2273
2274 /* Build hash table for initial edges */
2275 if ( !MMG5_hGeom(mesh) ) {
2276 fprintf(stderr,"\n ## Hashing problem (0). Exit program.\n");
2277 return 0;
2278 }
2279
2280 if ( !MMG5_bdrySet(mesh) ) {
2281 fprintf(stderr,"\n ## Problem in setting boundary. Exit program.\n");
2282 return 0;
2283 }
2284
2285 /* Reset the mesh->info.isoref field everywhere it appears */
2286 if ( !MMG3D_resetRef(mesh) ) {
2287 fprintf(stderr,"\n ## Problem in resetting references. Exit program.\n");
2288 return 0;
2289 }
2290
2291 /* Removal of small parasitic components */
2292 if ( mesh->info.iso ) {
2293 if ( mesh->info.rmc > 0. && !MMG3D_rmc(mesh,sol) ) {
2294 fprintf(stderr,"\n ## Error in removing small parasitic components."
2295 " Exit program.\n");
2296 return 0;
2297 }
2298 }
2299 else {
2300 /* RMC : on verra */
2301 if ( mesh->info.rmc > 0 ) {
2302 fprintf(stdout,"\n ## Warning: rmc option not implemented for boundary"
2303 " isosurface extraction.\n");
2304 }
2305 }
2306
2307#ifdef USE_POINTMAP
2308 /* Initialize source point with input index */
2309 MMG5_int ip;
2310 for( ip = 1; ip <= mesh->np; ip++ )
2311 mesh->point[ip].src = ip;
2312#endif
2313
2314 if ( !MMG3D_cuttet(mesh,sol,met) ) {
2315 fprintf(stderr,"\n ## Problem in discretizing implicit function. Exit program.\n");
2316 return 0;
2317 }
2318
2322
2323 mesh->nt = 0;
2324
2325 if ( !MMG3D_setref(mesh,sol) ) {
2326 fprintf(stderr,"\n ## Problem in setting references. Exit program.\n");
2327 return 0;
2328 }
2329
2330 /* Clean old bdy analysis */
2331 for ( MMG5_int k=1; k<=mesh->np; ++k ) {
2332 if ( mesh->point[k].tag & MG_BDY ) {
2333 mesh->point[k].tag &= ~MG_BDY;
2334 }
2335 }
2336
2337 /* Clean memory */
2338 MMG5_DEL_MEM(mesh,sol->m);
2339
2340 return 1;
2341}
int ier
tmp[*strlen0]
MMG5_pMesh MMG5_pSol * sol
if(!ier) exit(EXIT_FAILURE)
MMG5_pMesh * mesh
MMG5_Info info
#define MMG5_EPSD
#define MMG5_EPS
int MMG5_hashUpdate(MMG5_Hash *hash, MMG5_int a, MMG5_int b, MMG5_int k)
Definition: hash.c:404
int MMG5_hashNew(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int hsiz, MMG5_int hmax)
Definition: hash.c:532
MMG5_int MMG5_hashGet(MMG5_Hash *hash, MMG5_int a, MMG5_int b)
Definition: hash.c:501
int MMG5_hashEdge(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int a, MMG5_int b, MMG5_int k)
Definition: hash.c:346
int MMG3D_hashTetra(MMG5_pMesh mesh, int pack)
Create array of adjacency.
Definition: hash_3d.c:122
int MMG5_hGeom(MMG5_pMesh mesh)
Definition: hash_3d.c:1111
int MMG5_chkBdryTria(MMG5_pMesh mesh)
Definition: hash_3d.c:1559
int MMG5_bdrySet(MMG5_pMesh mesh)
Definition: hash_3d.c:1958
int MMG5_bdryPerm(MMG5_pMesh mesh)
Definition: hash_3d.c:2385
int MMG3D_intmet33_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int8_t i, MMG5_int ip, double s)
Definition: intmet_3d.c:126
int MMG5_intmet_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int8_t i, MMG5_int ip, double s)
Definition: intmet_3d.c:174
API headers and documentation for the mmg3d library, for volumetric meshes in 3D.
#define MMG3D_LMAX
Definition: libmmg3d.h:130
int MMG3D_cuttet_lssurf(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_pSol met)
Definition: mmg3d2s.c:160
int MMG5_split4op(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, MMG5_int vx[6], int8_t)
Definition: split_3d.c:3804
int MMG3D_snpval_lssurf(MMG5_pMesh mesh, MMG5_pSol sol)
Definition: mmg3d2s.c:107
int MMG5_split1(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, MMG5_int vx[6], int8_t metRidTyp)
Definition: split_3d.c:134
static const uint8_t MMG5_permedge[12][6]
MMG5_int MMG3D_indPt(MMG5_pMesh mesh, MMG5_int kp)
Definition: tools_3d.c:918
MMG5_int MMG3D_newPt(MMG5_pMesh mesh, double c[3], uint16_t tag, MMG5_int src)
Definition: zaldy_3d.c:39
static const int8_t MMG5_iarf[4][3]
iarf[i]: edges of face opposite to vertex i
static const uint8_t MMG5_iare[6][2]
vertices of extremities of the edges of the tetra
int MMG3D_setref_lssurf(MMG5_pMesh mesh, MMG5_pSol sol)
Definition: mmg3d2s.c:419
int MMG5_split2sf(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, MMG5_int vx[6], int8_t)
Definition: split_3d.c:1254
#define MMG3D_POINT_REALLOC(mesh, sol, ip, wantedGap, law, o, tag, src)
int MMG5_split3cone(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, MMG5_int vx[6], int8_t)
Definition: split_3d.c:2059
static const uint8_t MMG5_inxt3[7]
next vertex of tetra: {1,2,3,0,1,2,3}
int MMG3D_resetRef_lssurf(MMG5_pMesh mesh)
Definition: mmg3d2s.c:51
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
int MMG5_isLevelSet(MMG5_pMesh mesh, MMG5_int ref0, MMG5_int ref1)
Definition: mmg2.c:472
int MMG5_isNotSplit(MMG5_pMesh mesh, MMG5_int ref)
Definition: mmg2.c:448
static int MMG5_isbr(MMG5_pMesh mesh, MMG5_int ref)
Definition: mmg2.c:893
int MMG5_isSplit(MMG5_pMesh mesh, MMG5_int ref, MMG5_int *refint, MMG5_int *refext)
Definition: mmg2.c:412
int MMG5_getStartRef(MMG5_pMesh mesh, MMG5_int ref, MMG5_int *pref)
Definition: mmg2.c:213
int MMG3D_ismaniball(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_int k, int indp)
Definition: mmg3d2.c:407
int MMG3D_update_xtetra(MMG5_pMesh mesh)
Definition: mmg3d2.c:1310
int MMG3D_chkmanicoll(MMG5_pMesh mesh, MMG5_int k, int iface, int iedg, MMG5_int ndepmin, MMG5_int ndepplus, MMG5_int refmin, MMG5_int refplus, int8_t isminp, int8_t isplp)
Definition: mmg3d2.c:1683
int MMG3D_chkmaniball(MMG5_pMesh mesh, MMG5_int start, int8_t ip)
Definition: mmg3d2.c:1420
int MMG3D_chkmani2(MMG5_pMesh mesh, MMG5_pSol sol)
Definition: mmg3d2.c:1607
int MMG3D_setref_ls(MMG5_pMesh mesh, MMG5_pSol sol)
Definition: mmg3d2.c:1257
int MMG3D_chkmani(MMG5_pMesh mesh)
Definition: mmg3d2.c:1528
int MMG3D_mmg3d2(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_pSol met)
Definition: mmg3d2.c:2219
int MMG3D_cuttet_ls(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_pSol met)
Definition: mmg3d2.c:1026
static double MMG3D_vfrac_1vertex(MMG5_pPoint ppt[4], int8_t i0, double v[4], int8_t part_opp)
Definition: mmg3d2.c:58
int MMG3D_rmc(MMG5_pMesh mesh, MMG5_pSol sol)
Definition: mmg3d2.c:778
int8_t ddb
Definition: mmg3d1_delone.c:42
static int MMG5_invsl(double A[3][3], double b[3], double r[3])
Definition: mmg3d2.c:364
int MMG3D_snpval_ls(MMG5_pMesh mesh, MMG5_pSol sol)
Definition: mmg3d2.c:668
int MMG3D_resetRef_ls(MMG5_pMesh mesh)
Definition: mmg3d2.c:313
double MMG3D_vfrac(MMG5_pMesh mesh, MMG5_pSol sol, MMG5_int k, int pm)
Definition: mmg3d2.c:107
#define MG_REQ
#define MMG5_SAFE_CALLOC(ptr, size, type, law)
#define MMG5_EPSOK
#define MG_EOK(pt)
#define MMG5_INCREASE_MEM_MESSAGE()
#define MG_CLR(flag, bit)
#define MG_PARBDY
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#define MMG5_GAP
#define MMG5_ADD_MEM(mesh, size, message, law)
#define MMG5_SAFE_REALLOC(ptr, prevSize, newSize, type, message, law)
static const uint8_t MMG5_iprv2[3]
double MMG5_det4pt(double c0[3], double c1[3], double c2[3], double c3[3])
Definition: tools.c:932
#define MMG5_TAB_RECALLOC(mesh, ptr, initSize, wantedGap, type, message, law)
static const uint8_t MMG5_inxt2[6]
#define MG_VOK(ppt)
double MMG5_orvol(MMG5_pPoint point, MMG5_int *v)
Definition: tools.c:951
#define MG_BDY
#define MG_SMSGN(a, b)
#define MMG5_EPSD2
#define MMG5_DEL_MEM(mesh, ptr)
#define MG_SET(flag, bit)
#define MMG5_SAFE_RECALLOC(ptr, prevSize, newSize, type, message, law)
Identic as MMG5_HGeom but use MMG5_hedge to store edges instead of MMG5_hgeom (memory economy).
Definition: libmmgtypes.h:603
MMG5_hedge * item
Definition: libmmgtypes.h:605
int8_t iso
Definition: libmmgtypes.h:541
int8_t ddebug
Definition: libmmgtypes.h:539
int8_t isosurf
Definition: libmmgtypes.h:542
double rmc
Definition: libmmgtypes.h:526
MMG5_int isoref
Definition: libmmgtypes.h:528
double ls
Definition: libmmgtypes.h:526
MMG mesh structure.
Definition: libmmgtypes.h:613
size_t memCur
Definition: libmmgtypes.h:615
MMG5_Info info
Definition: libmmgtypes.h:659
MMG5_int xt
Definition: libmmgtypes.h:628
MMG5_int ne
Definition: libmmgtypes.h:620
MMG5_pPoint point
Definition: libmmgtypes.h:649
MMG5_int * adja
Definition: libmmgtypes.h:632
MMG5_int xtmax
Definition: libmmgtypes.h:620
MMG5_int nquad
Definition: libmmgtypes.h:621
MMG5_int npmax
Definition: libmmgtypes.h:620
MMG5_int base
Definition: libmmgtypes.h:624
MMG5_pTetra tetra
Definition: libmmgtypes.h:651
MMG5_int nt
Definition: libmmgtypes.h:620
MMG5_pTria tria
Definition: libmmgtypes.h:655
MMG5_int np
Definition: libmmgtypes.h:620
MMG5_pxTetra xtetra
Definition: libmmgtypes.h:652
MMG5_int nprism
Definition: libmmgtypes.h:621
MMG5_int npnil
Definition: libmmgtypes.h:629
MMG5_int * adjt
Definition: libmmgtypes.h:636
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 ref
Definition: libmmgtypes.h:284
MMG5_int flag
Definition: libmmgtypes.h:288
MMG5_int npmax
Definition: libmmgtypes.h:675
double * m
Definition: libmmgtypes.h:680
Structure to store tetrahedra of an MMG mesh.
Definition: libmmgtypes.h:407
MMG5_int v[4]
Definition: libmmgtypes.h:409
MMG5_int xt
Definition: libmmgtypes.h:413
MMG5_int flag
Definition: libmmgtypes.h:416
MMG5_int ref
Definition: libmmgtypes.h:410
uint16_t tag
Definition: libmmgtypes.h:417
double qual
Definition: libmmgtypes.h:408
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 ref[4]
Definition: libmmgtypes.h:426
uint16_t ftag[4]
Definition: libmmgtypes.h:430