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