Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
hash_3d.c
Go to the documentation of this file.
1/* =============================================================================
2** This file is part of the mmg software package for the tetrahedral
3** mesh modification.
4** Copyright (c) Bx INP/CNRS/Inria/UBordeaux/UPMC, 2004-
5**
6** mmg is free software: you can redistribute it and/or modify it
7** under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation, either version 3 of the License, or
9** (at your option) any later version.
10**
11** mmg is distributed in the hope that it will be useful, but WITHOUT
12** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13** FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14** License for more details.
15**
16** You should have received a copy of the GNU Lesser General Public
17** License and of the GNU General Public License along with mmg (in
18** files COPYING.LESSER and COPYING). If not, see
19** <http://www.gnu.org/licenses/>. Please read their terms carefully and
20** use this copy of the mmg distribution only if you accept them.
21** =============================================================================
22*/
23
35#include "libmmg3d.h"
36#include "libmmg3d_private.h"
37
38#define MMG5_KC 13
39
40extern int8_t ddb;
41
51 MMG5_pTetra pt,pt1;
52 MMG5_int k;
53
54 k = 1;
55 do {
56 pt = &mesh->tetra[k];
57 if ( !MG_EOK(pt) ) {
58 pt1 = &mesh->tetra[mesh->ne];
59 assert( pt && pt1 && MG_EOK(pt1) );
60 memcpy(pt,pt1,sizeof(MMG5_Tetra));
61 if ( !MMG3D_delElt(mesh,mesh->ne) ) return 0;
62 }
63 }
64 while ( ++k < mesh->ne );
65
66 /* Recreate nil chain */
67 assert(mesh->ne<=mesh->nemax);
68
69 if ( mesh->ne == mesh->nemax )
70 mesh->nenil = 0;
71 else {
72 mesh->nenil = mesh->ne + 1;
73
74 for(k=mesh->nenil; k<=mesh->nemax-1; k++){
75 mesh->tetra[k].v[3] = k+1;
76 }
77
78 mesh->tetra[mesh->nemax].v[3] = 0;
79 }
80 return 1;
81}
82
84MMG5_int MMG5_hashGetFace(MMG5_Hash *hash,MMG5_int ia,MMG5_int ib,MMG5_int ic) {
85 MMG5_hedge *ph;
86 MMG5_int key;
87 MMG5_int mins,maxs,sum;
88
89 if ( !hash->item ) return 0;
90
91 mins = MG_MIN(ia,MG_MIN(ib,ic));
92 maxs = MG_MAX(ia,MG_MAX(ib,ic));
93
94 /* compute key */
95 sum = ia + ib + ic;
96 key = (MMG5_KA*(int64_t)mins + MMG5_KB*(int64_t)maxs) % hash->siz;
97 ph = &hash->item[key];
98
99 if ( ph->a ) {
100 if ( ph->a == mins && ph->b == maxs && ph->s == sum )
101 return ph->k;
102 else {
103 while ( ph->nxt ) {
104 ph = &hash->item[ph->nxt];
105 if ( ph->a == mins && ph->b == maxs && ph->s == sum ) return ph->k;
106 }
107 }
108 }
109
110 return 0;
111}
112
123 MMG5_pTetra pt,pt1;
124 MMG5_int key;
125 MMG5_int k,kk,pp,l,ll,mins,mins1,maxs,maxs1,sum,sum1,iadr;
126 MMG5_int *hcode,*link,hsize,inival;
127 uint8_t i,ii,i1,i2,i3;
128
129 /* default */
130 if ( mesh->adja ) {
131 return 1;
132 }
133
134 if ( abs(mesh->info.imprim) > 5 || mesh->info.ddebug )
135 fprintf(stdout," ** SETTING STRUCTURE\n");
136
137 /* packing : if not hash does not work */
138 if ( pack ) {
139 if ( ! MMG5_paktet(mesh) ) return 0;
140 }
141
142 /* memory alloc */
143 MMG5_ADD_MEM(mesh,(4*mesh->nemax+5)*sizeof(MMG5_int),"adjacency table",
144 fprintf(stderr," Exit program.\n");
145 return 0);
146 MMG5_SAFE_CALLOC(mesh->adja,4*mesh->nemax+5,MMG5_int,return 0);
147 MMG5_SAFE_CALLOC(hcode,mesh->ne+5,MMG5_int,return 0);
148
149 link = mesh->adja;
150 hsize = mesh->ne;
151
152 /* init */
153 if ( mesh->info.ddebug ) fprintf(stdout," h- stage 1: init\n");
154
155 inival = MMG5_INTMAX;
156
157 iadr = 0;
158 for (k=0; k<=mesh->ne; k++)
159 hcode[k] = -inival;
160
161 /* hash tetras */
162 for (k=1; k<=mesh->ne; k++) {
163 pt = &mesh->tetra[k];
164 if ( !MG_EOK(pt) ) continue;
165 for (i=0; i<4; i++) {
166 i1 = MMG5_idir[i][0];
167 i2 = MMG5_idir[i][1];
168 i3 = MMG5_idir[i][2];
169 mins = MG_MIN(pt->v[i1],MG_MIN(pt->v[i2],pt->v[i3]));
170 maxs = MG_MAX(pt->v[i1],MG_MAX(pt->v[i2],pt->v[i3]));
171
172 /* compute key and insert */
173 sum = pt->v[i1] + pt->v[i2] + pt->v[i3];
174 key = (MMG5_KA*(int64_t)mins+MMG5_KB*(int64_t)maxs+MMG5_KC*(int64_t)sum)%hsize+1;
175 iadr++;
176 link[iadr] = hcode[key];
177 hcode[key] = -iadr;
178 }
179 }
180
181 /* set adjacency */
182 if ( mesh->info.ddebug ) fprintf(stdout," h- stage 2: adjacencies\n");
183 for (l=iadr; l>0; l--) {
184 if ( link[l] >= 0 ) continue;
185
186 /* current element */
187 k = (l-1) / 4 + 1;
188 i = (l-1) % 4;
189 i1 = MMG5_idir[i][0];
190 i2 = MMG5_idir[i][1];
191 i3 = MMG5_idir[i][2];
192 pt = &mesh->tetra[k];
193 mins = MG_MIN(pt->v[i1],MG_MIN(pt->v[i2],pt->v[i3]));
194 maxs = MG_MAX(pt->v[i1],MG_MAX(pt->v[i2],pt->v[i3]));
195 sum = pt->v[i1] + pt->v[i2] + pt->v[i3];
196
197 /* accross link */
198 ll = -link[l];
199 pp = 0;
200 link[l] = 0;
201 while ( ll != inival ) {
202 kk = (ll-1) / 4 + 1;
203 ii = (ll-1) % 4;
204 i1 = MMG5_idir[ii][0];
205 i2 = MMG5_idir[ii][1];
206 i3 = MMG5_idir[ii][2];
207 pt1 = &mesh->tetra[kk];
208 sum1 = pt1->v[i1] + pt1->v[i2] + pt1->v[i3];
209 if ( sum1 == sum ) {
210 mins1 = MG_MIN(pt1->v[i1],MG_MIN(pt1->v[i2],pt1->v[i3]));
211 maxs1 = MG_MAX(pt1->v[i1],MG_MAX(pt1->v[i2],pt1->v[i3]));
212
213 /* adjacent found */
214 if ( mins1 == mins && maxs1 == maxs ) {
215 if ( pp != 0 ) link[pp] = link[ll];
216 link[l] = 4*kk + ii;
217 link[ll] = 4*k + i;
218 break;
219 }
220 }
221 pp = ll;
222 ll = -link[ll];
223 }
224 }
225 MMG5_SAFE_FREE(hcode);
226 return 1;
227}
228
241 MMG5_pPrism pp,pp1;
242 MMG5_int key;
243 MMG5_int k,kk,l,ll,jj;
244 MMG5_int max12,min12,max34,min34,mins,mins1,mins_b, mins_b1,maxs,maxs1;
245 MMG5_int iadr;
246 MMG5_int *hcode,*link,hsize,inival;
247 uint8_t i,ii,i1,i2,i3,i4;
248
249 if ( !mesh->nprism ) return 1;
250
251 /* default */
252 if ( mesh->adjapr ) {
253 if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) {
254 fprintf(stderr,"\n ## Warning: %s: no re-build of adjacencies of prisms. "
255 "mesh->adjapr must be freed to enforce analysis.\n",__func__);
256 }
257 return 1;
258 }
259
260 if ( abs(mesh->info.imprim) > 5 || mesh->info.ddebug )
261 fprintf(stdout," ** SETTING PRISMS ADJACENCY\n");
262
263 /* memory alloc */
264 MMG5_ADD_MEM(mesh,(5*mesh->nprism+6)*sizeof(MMG5_int),"prism adjacency table",
265 printf(" Exit program.\n");
266 return 0);
267 MMG5_SAFE_CALLOC(mesh->adjapr,5*mesh->nprism+6,MMG5_int,return 0);
268 MMG5_SAFE_CALLOC(hcode,mesh->nprism+6,MMG5_int,return 0);
269
270 link = mesh->adjapr;
271 hsize = mesh->nprism;
272
273 /* init */
274 if ( mesh->info.ddebug ) fprintf(stdout," h- stage 1: init\n");
275
276 inival = MMG5_INTMAX;
277
278 iadr = 0;
279 for (k=0; k<=mesh->nprism; k++)
280 hcode[k] = -inival;
281
282 /* hash prism */
283 for (k=1; k<=mesh->nprism; k++) {
284 pp = &mesh->prism[k];
285 assert ( MG_EOK(pp) );
286 for (i=0; i<2; i++) {
287 /* Triangular face */
288 i1 = MMG5_idir_pr[i][0];
289 i2 = MMG5_idir_pr[i][1];
290 i3 = MMG5_idir_pr[i][2];
291
292 min12 = MG_MIN(pp->v[i1],pp->v[i2]);
293 /* mins = minimum index of triangle vertices */
294 mins = MG_MIN(min12,pp->v[i3]);
295
296 max12 = MG_MAX(pp->v[i1],pp->v[i2]);
297 /* maxs = maximum index of triangle vertices */
298 maxs = MG_MAX(max12,pp->v[i3]);
299
300 /* mins_b = second minimum index of triangle vertices */
301 mins_b = pp->v[i1] + pp->v[i2] + pp->v[i3] -mins -maxs;
302
303 /* compute key and insert */
304 key = (MMG5_KA*(int64_t)mins+MMG5_KB*(int64_t)mins_b+MMG5_KC*(int64_t)maxs)%hsize+1;
305 iadr++;
306 link[iadr] = hcode[key];
307 hcode[key] = -iadr;
308 }
309 for ( ; i<5; ++i) {
310 /* Quadrilateral face */
311 i1 = MMG5_idir_pr[i][0];
312 i2 = MMG5_idir_pr[i][1];
313 i3 = MMG5_idir_pr[i][2];
314 i4 = MMG5_idir_pr[i][3];
315
316 min12 = MG_MIN(pp->v[i1],pp->v[i2]);
317 min34 = MG_MIN(pp->v[i3],pp->v[i4]);
318 /* mins = minimum index of quadrilateral vertices */
319 mins = MG_MIN(min12,min34);
320
321 max12 = MG_MAX(pp->v[i1],pp->v[i2]);
322 max34 = MG_MAX(pp->v[i3],pp->v[i4]);
323 /* maxs = maximum index of quadrilateral vertices */
324 maxs = MG_MAX(max12,max34);
325
326 /* mins_b = second minimum index of quadrilateral vertices */
327 mins_b = MG_MIN( MG_MIN(max12,max34),MG_MAX(min12,min34));
328
329 /* compute key and insert */
330 key = (MMG5_KA*(int64_t)mins+MMG5_KB*(int64_t)mins_b+MMG5_KC*(int64_t)maxs)%hsize+1;
331 iadr++;
332 link[iadr] = hcode[key];
333 hcode[key] = -iadr;
334 }
335 }
336
337 /* set adjacency */
338 if ( mesh->info.ddebug ) fprintf(stdout," h- stage 2: adjacencies\n");
339 for (l=iadr; l>0; l--) {
340 if ( link[l] >= 0 ) continue;
341
342 /* current element */
343 k = (l-1) / 5 + 1;
344 i = (l-1) % 5;
345
346 switch (i)
347 {
348 case 0:
349 case 1:
350 i1 = MMG5_idir_pr[i][0];
351 i2 = MMG5_idir_pr[i][1];
352 i3 = MMG5_idir_pr[i][2];
353 pp = &mesh->prism[k];
354
355 min12 = MG_MIN(pp->v[i1],pp->v[i2]);
356 mins = MG_MIN(min12,pp->v[i3]);
357
358 max12 = MG_MAX(pp->v[i1],pp->v[i2]);
359 maxs = MG_MAX(max12,pp->v[i3]);
360
361 mins_b = pp->v[i1] + pp->v[i2] + pp->v[i3] - mins - maxs;
362
363 break;
364
365 default:
366 i1 = MMG5_idir_pr[i][0];
367 i2 = MMG5_idir_pr[i][1];
368 i3 = MMG5_idir_pr[i][2];
369 i4 = MMG5_idir_pr[i][3];
370 pp = &mesh->prism[k];
371
372 min12 = MG_MIN(pp->v[i1],pp->v[i2]);
373 min34 = MG_MIN(pp->v[i3],pp->v[i4]);
374 mins = MG_MIN(min12,min34);
375
376 max12 = MG_MAX(pp->v[i1],pp->v[i2]);
377 max34 = MG_MAX(pp->v[i3],pp->v[i4]);
378 maxs = MG_MAX(max12,max34);
379
380 mins_b = MG_MIN( MG_MIN(max12,max34),MG_MAX(min12,min34));
381 }
382
383 /* accross link */
384 ll = -link[l];
385 jj = 0;
386 link[l] = 0;
387 while ( ll != inival ) {
388 kk = (ll-1) / 5 + 1;
389 ii = (ll-1) % 5;
390
391 switch (ii)
392 {
393 case 0:
394 case 1:
395 i1 = MMG5_idir_pr[ii][0];
396 i2 = MMG5_idir_pr[ii][1];
397 i3 = MMG5_idir_pr[ii][2];
398
399 pp1 = &mesh->prism[kk];
400
401 min12 = MG_MIN(pp1->v[i1],pp1->v[i2]);
402 mins1 = MG_MIN(min12,pp1->v[i3]);
403
404 max12 = MG_MAX(pp1->v[i1],pp1->v[i2]);
405 maxs1 = MG_MAX(max12,pp1->v[i3]);
406
407 mins_b1 = pp1->v[i1] + pp1->v[i2] + pp1->v[i3] - mins1 - maxs1;
408
409 break;
410
411 default:
412 i1 = MMG5_idir_pr[ii][0];
413 i2 = MMG5_idir_pr[ii][1];
414 i3 = MMG5_idir_pr[ii][2];
415 i4 = MMG5_idir_pr[ii][3];
416 pp1 = &mesh->prism[kk];
417
418 min12 = MG_MIN(pp1->v[i1],pp1->v[i2]);
419 min34 = MG_MIN(pp1->v[i3],pp1->v[i4]);
420 mins1 = MG_MIN(min12,min34);
421
422 max12 = MG_MAX(pp1->v[i1],pp1->v[i2]);
423 max34 = MG_MAX(pp1->v[i3],pp1->v[i4]);
424 maxs1 = MG_MAX(max12,max34);
425
426 mins_b1 = MG_MIN( MG_MIN(max12,max34),MG_MAX(min12,min34));
427 }
428
429 /* adjacent found */
430 if ( mins1 == mins && maxs1 == maxs && mins_b1 == mins_b ) {
431 if ( jj != 0 ) link[jj] = link[ll];
432 link[l] = 5*kk + ii;
433 link[ll] = 5*k + i;
434 break;
435 }
436
437 jj = ll;
438 ll = -link[ll];
439 }
440 }
441 MMG5_SAFE_FREE(hcode);
442 return 1;
443}
444
459static inline
461 MMG5_pTetra pt;
462 MMG5_pxTetra pxt;
463 MMG5_pTria ptt;
464 MMG5_hedge *ph;
465 MMG5_int adj,pradj,piv;
466 int64_t list[MMG3D_LMAX+2];
467 MMG5_int key;
468 MMG5_int k,l,i1,i2,na,nb,ia,it1,it2, nr;
469 MMG5_int start;
470 int ilist,nbdy,ipa,ipb;
471 int8_t iface,hasadja,i;
472 static int8_t mmgWarn0=0,mmgWarn1=0;
473
474 nr = 0;
475
476 /* First: seek edges at the interface of two distinct domains and mark it as
477 * required */
478 for (k=1; k<=mesh->nt; k++) {
479 ptt = &mesh->tria[k];
480
481 if ( !MG_EOK(ptt) ) continue;
482
483 for (l=0; l<3; l++) {
484
485 /* Skip parallel edges */
486 if ( (ptt->tag[l] & MG_PARBDY) || (ptt->tag[l] & MG_BDY) ) continue;
487
488 if ( ptt->tag[l] & MG_NOM ) {
489 i1 = MMG5_inxt2[l];
490 i2 = MMG5_iprv2[l];
491
492 /* compute key */
493 na = MG_MIN(ptt->v[i1],ptt->v[i2]);
494 nb = MG_MAX(ptt->v[i1],ptt->v[i2]);
495 key = (MMG5_KA*na + MMG5_KB*nb) % hash->siz;
496 ph = &hash->item[key];
497
498 assert(ph->a);
499 while ( ph->a ) {
500 if ( ph->a == na && ph->b == nb ) break;
501 assert(ph->nxt);
502 ph = &hash->item[ph->nxt];
503 }
504 /* Set edge tag and point tags to MG_REQ if the non-manifold edge shared
505 * separated domains */
506 if ( ph->s > 3 ) {
507 start = ptt->cc/4;
508 assert(start);
509 pt = &mesh->tetra[start];
510
511
512 for (ia=0; ia<6; ++ia) {
513 ipa = MMG5_iare[ia][0];
514 ipb = MMG5_iare[ia][1];
515 if ( (pt->v[ipa] == na && pt->v[ipb] == nb) ||
516 (pt->v[ipa] == nb && pt->v[ipb] == na)) break;
517 }
518 assert(ia<6);
519
520
521 /* Travel throug the shell of the edge until reaching a tetra without adjacent
522 * or until reaching the starting tetra */
523 iface = ptt->cc%4;
524 MMG3D_coquilFaceFirstLoop(mesh,start,na,nb,iface,ia,list,&ilist,&it1,&it2,
525 &piv,&adj,&hasadja,&nbdy,1);
526
527 /* At this point, the first travel, in one direction, of the shell is
528 complete. Now, analyze why the travel ended. */
529 if ( adj == start ) {
530 if ( !it2 ) {
531 if ( !mmgWarn0 ) {
532 mmgWarn0 = 1;
533 fprintf(stderr,"\n ## Warning: %s: at least 1 wrong boundary tag:"
534 " Only 0 or 1 boundary triangles founded in the shell of the edge\n",
535 __func__);
536 }
537 }
538 if ( nbdy < 2 )
539 MMG5_coquilFaceErrorMessage(mesh, it1/4, it2/4);
540 }
541 else {
542 /* A boundary has been detected : slightly different configuration */
543 if ( hasadja ) {
544
545 /* Start back everything from this tetra adj */
546 MMG3D_coquilFaceSecondLoopInit(mesh,piv,&iface,&i,list,&ilist,&it1,
547 &pradj,&adj);
548
549 nbdy = 1;
550 while ( adj ) {
551 pradj = adj;
552
553 if ( MMG5_openCoquilTravel(mesh,na,nb,&adj,&piv,&iface,&i)<0 ) {
554 return 0;
555 }
556
557 /* overflow */
558 if ( ++ilist > MMG3D_LMAX-2 ) {
559 if ( !mmgWarn1 ) {
560 mmgWarn1 = 1;
561 fprintf(stderr,"\n ## Warning: %s: problem in surface remesh"
562 " process. At least 1 shell of edge (%" MMG5_PRId "-%" MMG5_PRId ") contains"
563 " too many elts.\n",__func__,MMG3D_indPt(mesh,na),
564 MMG3D_indPt(mesh,nb));
565 fprintf(stderr,"\n ## Try to modify the hausdorff"
566 " number, or/and the maximum mesh.\n");
567 }
568 return 0;
569 }
570
571 pt = &mesh->tetra[pradj];
572 if ( pt->xt ) {
573 pxt = &mesh->xtetra[pt->xt];
574 if ( pxt->ftag[iface] & MG_BDY ) ++nbdy;
575 }
576 }
577
578 assert(!adj);
579 it2 = 4*pradj + iface;
580
581 if ( (!it1 || !it2) || (it1 == it2) ) {
582 MMG5_coquilFaceErrorMessage(mesh, it1/4, it2/4);
583 return 0;
584 }
585 }
586 }
587
588 /* If ph->s do not match the number of encountred boundaries we have
589 separated domains. */
590 if ( nbdy != ph->s ) {
591 if ( !(ptt->tag[l] & MG_REQ) ) {
592 ptt->tag[l] |= MG_REQ;
593 ptt->tag[l] &= ~MG_NOSURF;
594 ++nr;
595 }
596 mesh->point[ptt->v[MMG5_inxt2[l]]].tag |= MG_REQ;
597 mesh->point[ptt->v[MMG5_iprv2[l]]].tag |= MG_REQ;
598 mesh->point[ptt->v[MMG5_inxt2[l]]].tag &= ~MG_NOSURF;
599 mesh->point[ptt->v[MMG5_iprv2[l]]].tag &= ~MG_NOSURF;
600 }
601
602 /* Work done for this edge: reset ph->s/ */
603 ph->s = 0;
604 }
605 }
606 }
607 }
608 if ( mesh->info.ddebug || abs(mesh->info.imprim) > 3 )
609 fprintf(stdout," %" MMG5_PRId " required edges added\n",nr);
610
611 /* Free the edge hash table */
612 MMG5_DEL_MEM(mesh,hash->item);
613 return 1;
614}
615
616
617static inline
618uint16_t MMG5_skip_ParBdy ( uint16_t tag ) {
619 return (tag & MG_PARBDY);
620}
621
637int MMG5_setVertexNmTag(MMG5_pMesh mesh,uint16_t func(uint16_t) ) {
638 MMG5_pTetra ptet;
639 MMG5_pPoint ppt0,ppt1;
640 MMG5_Hash hash;
641 int i,ier;
642 MMG5_int k,np,nc,nre,*nfeat,*tmp;
643
648 np = 0;
649 MMG5_SAFE_MALLOC(tmp,mesh->np+1,MMG5_int,return 0);
650
651 for (k=1; k<=mesh->np; ++k) {
652 ppt0 = &mesh->point[k];
653 if ( !MG_VOK(ppt0) ) {
654 tmp[k] = 0;
655 }
656 else if ( ppt0->tag & MG_REQ || func(ppt0->tag) ) {
657 /* Skip required points and points satisfying condition "func". For
658 * "classic" analysis, func test if the point is PARBDY, between ParMmg
659 * iterations, it tests if the point is not an old PARBDY point (we want
660 * to update analysis only on old parbdy points so we skip the other
661 * ones). */
662 tmp[k] = 0;
663 }
664 else if ( !(ppt0->tag & MG_NOM) ) {
665 /* Skip manifold points */
666 tmp[k] = 0;
667 }
668 else {
669 tmp[k] = ++np;
670 }
671 }
672
673 /* Array to store info of incident feature edges at points */
674 MMG5_SAFE_CALLOC(nfeat,3*(np+1),MMG5_int,return 0);
675
676 /* Hash table to store the list of seen feature edges */
677 if ( ! MMG5_hashNew(mesh,&hash,np,(MMG5_int)(3.71*np)) ) return 0;
678
679 for (k=1; k<=mesh->ne; ++k) {
680 ptet = &mesh->tetra[k];
681
682 if ( !MG_EOK(ptet) ) continue;
683 if ( !ptet->xt ) continue;
684
685 MMG5_pxTetra pxt = &mesh->xtetra[ptet->xt];
686
687 for ( i=0; i<6; ++i ) {
688 MMG5_int np0 = ptet->v[MMG5_iare[i][0]];
689 MMG5_int np1 = ptet->v[MMG5_iare[i][1]];
690
691 ppt0 = &mesh->point[np0];
692 ppt1 = &mesh->point[np1];
693
694 if ( ! MG_EDG_OR_NOM(pxt->tag[i]) ) {
695 continue;
696 }
697
698 /* Here we have a feature edge: seek if we have already seen it. If not,
699 * hash it and increment nfeat: for point ppt, nfeat[3*tmp] stores
700 * the number of ridges passing through the point, nfeat[3*tmp+1]
701 * stores the number of reference edges, nfeat[3*ppt->tmp+2] the number of
702 * non-manifold edges.*/
703 assert ( MG_VOK(ppt1) && MG_VOK(ppt0) );
704
705 if ( (!tmp[np0]) && (!tmp[np1]) ) {
706 continue;
707 }
708
709 ier = MMG5_hashEdge(mesh,&hash,np0,np1,0);
710 if ( ier == 1 ) {
711 /* Edge has been already seen */
712 continue;
713 }
714 else if ( !ier ) {
715 return 0;
716 }
717
718 if ( pxt->tag[i] & MG_GEO ) {
719 ++nfeat[3*tmp[np0]];
720 }
721 else if ( pxt->tag[i] & MG_NOM ) {
722 ++nfeat[3*tmp[np0]+1];
723 }
724 else if ( pxt->tag[i] & MG_REF ) {
725 ++nfeat[3*tmp[np0]+2];
726 }
727
728 if ( pxt->tag[i] & MG_GEO ) {
729 ++nfeat[3*tmp[np1]];
730 }
731 else if ( pxt->tag[i] & MG_NOM ) {
732 ++nfeat[3*tmp[np1]+1];
733 }
734 else if ( pxt->tag[i] & MG_REF ) {
735 ++nfeat[3*tmp[np1]+2];
736 }
737 }
738 }
739
741 nc = nre = 0;
742 for (k=1; k<=mesh->np; ++k) {
743 ppt0 = &mesh->point[k];
744
745 if ( (!MG_VOK(ppt0)) || (!tmp[k]) ) {
746 continue;
747 }
748
749 MMG5_int ng = nfeat[3*tmp[k]];
750 MMG5_int nrp = nfeat[3*tmp[k]+1];
751 MMG5_int nm = nfeat[3*tmp[k]+2];
752
753 if ( (ng+nrp+nm) > 2 ) {
754 /* More than 2 feature edges are passing through the point: point is
755 * marked as corner */
756 ppt0->tag |= MG_CRN + MG_REQ;
757 ppt0->tag &= ~MG_NOSURF;
758 nre++;
759 nc++;
760 }
761 else if ( (ng == 2) || (nrp == 2) || (nm == 2) ) {
762 /* Exactly 2 edges of same type are passing through the point: do
763 * nothing */
764 continue;
765 }
766 else if ( (ng+nrp+nm) == 2 ) {
767 /* 2 edges of different type are passing through the point: point is
768 * marked as required */
769 ppt0->tag |= MG_REQ;
770 ppt0->tag &= ~MG_NOSURF;
771 nre++;
772 }
773 else if ( ng == 1 && !nrp ){
774 ppt0->tag |= MG_CRN + MG_REQ;
775 ppt0->tag &= ~MG_NOSURF;
776 nre++;
777 nc++;
778 }
779 else if ( (ng+nrp+nm) == 1 ){
780 /* Only 1 feature edge is passing through the point: point is
781 * marked as corner */
782 assert ( (ng == 1) || (nrp==1) || (nm==1) );
783 ppt0->tag |= MG_CRN + MG_REQ;
784 ppt0->tag &= ~MG_NOSURF;
785 nre++;
786 nc++;
787 }
788 /* "else" case may happens: ng = nrp = nm = 0 inside hybrid meshes (along a
789 * non manifold line along a surface at the interface of hexahedral domains
790 * with different refs). No need to set tags at points as they will not be
791 * modified. */
792 }
793
794 /* Free the edge hash table */
796 MMG5_SAFE_FREE(nfeat);
797 MMG5_DEL_MEM(mesh,hash.item);
798
799 if ( mesh->info.ddebug || abs(mesh->info.imprim) > 3 )
800 fprintf(stdout," %" MMG5_PRId " corner and %" MMG5_PRId " required vertices added\n",nc,nre);
801
802 return 1;
803}
804
817
818 /* First: seek edges at the interface of two distinct domains and mark it as
819 * required */
820 if ( !MMG5_setEdgeNmTag(mesh,hash) ) return 0;
821
822 /* Second: seek the non-required non-manifold points and try to analyse
823 * whether they are corner or required. */
824 if ( !MMG5_setVertexNmTag(mesh,MMG5_skip_ParBdy) ) return 0;
825
826 return 1;
827}
828
839
841
842 MMG5_ADD_MEM(mesh,(3*mesh->nt+4)*sizeof(MMG5_int),"surfacic adjacency table",return 0);
843 MMG5_SAFE_CALLOC(mesh->adjt,3*mesh->nt+4,MMG5_int,return 0);
844
845 return MMG5_mmgHashTria(mesh, mesh->adjt, hash, mesh->info.iso) ;
846}
847
848
850int MMG5_hashPop(MMG5_Hash *hash,MMG5_int a,MMG5_int b) {
851 MMG5_hedge *ph,*php;
852 MMG5_int key;
853 MMG5_int ia,ib,iph,iphp;
854
855 ia = MG_MIN(a,b);
856 ib = MG_MAX(a,b);
857 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
858 ph = &hash->item[key];
859
860 if ( !ph->a ) return 0;
861 else if ( ph->a == ia && ph->b == ib ) {
862 if ( !ph->nxt ) {
863 memset(ph,0,sizeof(MMG5_hedge));
864 return 1;
865 }
866 else {
867 iph = ph->nxt;
868 php = ph;
869 ph = &hash->item[ph->nxt];
870 memcpy(php,ph,sizeof(MMG5_hedge));
871 memset(ph,0,sizeof(MMG5_hedge));
872 ph->nxt = hash->nxt;
873 hash->nxt = iph;
874 return 1;
875 }
876 }
877 while ( ph->nxt ) {
878 php = ph;
879 ph = &hash->item[ph->nxt];
880 if ( ph->a == ia && ph->b == ib ) {
881 if ( !ph->nxt ) {
882 memset(ph,0,sizeof(MMG5_hedge));
883 ph->nxt = hash->nxt;
884 hash->nxt = php->nxt;
885 php->nxt = 0;
886 }
887 else {
888 iph = ph->nxt;
889 iphp = php->nxt;
890 php->nxt = iph;
891 memset(ph,0,sizeof(MMG5_hedge));
892 ph->nxt = hash->nxt;
893 hash->nxt = iphp;
894 }
895 return 1;
896 }
897 }
898 return 0;
899}
900
901
914int MMG5_hTag(MMG5_HGeom *hash,MMG5_int a,MMG5_int b,MMG5_int ref,uint16_t tag) {
915 MMG5_hgeom *ph;
916 MMG5_int key;
917 MMG5_int ia,ib;
918
919 ia = MG_MIN(a,b);
920 ib = MG_MAX(a,b);
921 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
922 ph = &hash->geom[key];
923
924 if ( !ph->a )
925 return 0;
926 else if ( ph->a == ia && ph->b == ib ) {
927 ph->tag |= tag;
928 if ( ref ) {
929 ph->ref = ref;
930 }
931 return 1;
932 }
933 while ( ph->nxt ) {
934 ph = &hash->geom[ph->nxt];
935 if ( ph->a == ia && ph->b == ib ) {
936 ph->tag |= tag;
937 if ( ref ) {
938 ph->ref = ref;
939 }
940 return 1;
941 }
942 }
943 return 0;
944}
945
947int MMG5_hPop(MMG5_HGeom *hash,MMG5_int a,MMG5_int b,MMG5_int *ref,uint16_t *tag) {
948 MMG5_hgeom *ph,*php;
949 MMG5_int key;
950 MMG5_int ia,ib,iph,iphp;
951
952 *ref = 0;
953 *tag = 0;
954
955 assert ( hash->siz );
956
957 ia = MG_MIN(a,b);
958 ib = MG_MAX(a,b);
959 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
960 ph = &hash->geom[key];
961
962 if ( !ph->a ) return 0;
963 else if ( ph->a == ia && ph->b == ib ) {
964 *ref = ph->ref;
965 *tag = ph->tag;
966 if ( !ph->nxt ) {
967 memset(ph,0,sizeof(MMG5_hgeom));
968 }
969 else {
970 iph = ph->nxt;
971 php = ph;
972 ph = &hash->geom[ph->nxt];
973 memcpy(php,ph,sizeof(MMG5_hgeom));
974 memset(ph,0,sizeof(MMG5_hgeom));
975 ph->nxt = hash->nxt;
976 hash->nxt = iph;
977 }
978 return 1;
979 }
980 while ( ph->nxt ) {
981 php = ph;
982 ph = &hash->geom[ph->nxt];
983 if ( ph->a == ia && ph->b == ib ) {
984 *ref = ph->ref;
985 *tag = ph->tag;
986 if ( !ph->nxt ) {
987 memset(ph,0,sizeof(MMG5_hgeom));
988 ph->nxt = hash->nxt;
989 hash->nxt = php->nxt;
990 php->nxt = 0;
991 }
992 else {
993 iph = ph->nxt;
994 iphp = php->nxt;
995 php->nxt = iph;
996 memset(ph,0,sizeof(MMG5_hgeom));
997 ph->nxt = hash->nxt;
998 hash->nxt = iphp;
999 }
1000 return 1;
1001 }
1002 }
1003 return 0;
1004}
1005
1007int MMG5_hGet(MMG5_HGeom *hash,MMG5_int a,MMG5_int b,MMG5_int *ref,uint16_t *tag) {
1008 MMG5_hgeom *ph;
1009 MMG5_int key;
1010 MMG5_int ia,ib;
1011
1012 *tag = 0;
1013 *ref = 0;
1014
1015 assert ( hash->siz );
1016
1017 ia = MG_MIN(a,b);
1018 ib = MG_MAX(a,b);
1019 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
1020 ph = &hash->geom[key];
1021
1022 if ( !ph->a ) return 0;
1023 else if ( ph->a == ia && ph->b == ib ) {
1024 *ref = ph->ref;
1025 *tag = ph->tag;
1026 return 1;
1027 }
1028 while ( ph->nxt ) {
1029 ph = &hash->geom[ph->nxt];
1030 if ( ph->a == ia && ph->b == ib ) {
1031 *ref = ph->ref;
1032 *tag = ph->tag;
1033 return 1;
1034 }
1035 }
1036 return 0;
1037}
1038
1040int MMG5_hEdge(MMG5_pMesh mesh,MMG5_HGeom *hash,MMG5_int a,MMG5_int b,MMG5_int ref,uint16_t tag) {
1041 MMG5_hgeom *ph;
1042 MMG5_int key;
1043 MMG5_int ia,ib,j;
1044
1045 assert ( hash->siz );
1046
1047 ia = MG_MIN(a,b);
1048 ib = MG_MAX(a,b);
1049 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
1050 ph = &hash->geom[key];
1051
1052 if ( ph->a == ia && ph->b == ib )
1053 return 1;
1054 else if ( ph->a ) {
1055 while ( ph->nxt ) {
1056 ph = &hash->geom[ph->nxt];
1057 if ( ph->a == ia && ph->b == ib ) return 1;
1058 }
1059 ph->nxt = hash->nxt;
1060 ph = &hash->geom[hash->nxt];
1061 ph->a = ia; ph->b = ib;
1062 ph->ref = ref; ph->tag = tag;
1063 hash->nxt = ph->nxt;
1064 ph->nxt = 0;
1065 if ( hash->nxt >= hash->max ) {
1066 if ( mesh->info.ddebug )
1067 fprintf(stderr,"\n ## Memory alloc problem (edge): %" MMG5_PRId "\n",hash->max);
1069 "larger htab table",
1070 fprintf(stderr," Exit program.\n");return 0;);
1071 for (j=hash->nxt; j<hash->max; j++) hash->geom[j].nxt = j+1;
1072 }
1073 return 1;
1074 }
1075 /* insert new edge */
1076 ph->a = ia; ph->b = ib;
1077 ph->ref = ref; ph->tag = tag;
1078 ph->nxt = 0;
1079 return 1;
1080}
1081
1083int MMG5_hNew(MMG5_pMesh mesh,MMG5_HGeom *hash,MMG5_int hsiz,MMG5_int hmax) {
1084 MMG5_int k;
1085
1086 /* adjust hash table params */
1087 hash->siz = hsiz + 1;
1088 hash->max = hmax + 2;
1089 hash->nxt = hash->siz;
1090
1091 MMG5_ADD_MEM(mesh,(hash->max+1)*sizeof(MMG5_hgeom),"Edge hash table",return 0);
1092 MMG5_SAFE_CALLOC(hash->geom,(hash->max+1),MMG5_hgeom,return 0);
1093
1094 if ( !hash->geom ) {
1095 perror(" ## Memory problem: calloc");
1096 return 0;
1097 }
1098 for (k=hash->siz; k<hash->max; k++)
1099 hash->geom[k].nxt = k+1;
1100
1101 return 1;
1102}
1103
1112 MMG5_pTria pt;
1113 MMG5_pEdge pa;
1114 MMG5_Hash hash;
1115 MMG5_int edg,*adja,k,kk;
1116 int ier;
1117 uint16_t tag;
1118 int8_t i,i1,i2;
1119
1120 /* if edges exist in mesh, hash special edges from existing field */
1121 if ( mesh->na ) {
1122 if ( !mesh->htab.geom ) {
1123 mesh->namax = MG_MAX((MMG5_int)(1.5*mesh->na),MMG3D_NAMAX);
1124 if ( !MMG5_hNew(mesh,&mesh->htab,mesh->na,3*mesh->namax) )
1125 return 0;
1126 }
1127 else {
1128 if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) {
1129 fprintf(stderr,"\n ## Warning: %s: no re-hash of edges of mesh. ",
1130 __func__);
1131 fprintf(stderr,"mesh->htab.geom must be freed to enforce analysis.\n");
1132 }
1134 mesh->na = 0;
1135 return 1;
1136 }
1137
1138 /* store initial edges */
1139 for (k=1; k<=mesh->na; k++) {
1140 pa = &mesh->edge[k];
1141 if ( !MMG5_hEdge(mesh,&mesh->htab,pa->a,pa->b,pa->ref,pa->tag) )
1142 return 0;
1143 }
1144
1145 /* now check triangles */
1146 for (k=1; k<=mesh->nt; k++) {
1147 pt = &mesh->tria[k];
1148 for (i=0; i<3; i++) {
1149 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
1150 i1 = MMG5_inxt2[i];
1151 i2 = MMG5_iprv2[i];
1152 /* transfer non manifold tag to edges */
1153 if ( pt->tag[i] & MG_NOM ) {
1154 ier = MMG5_hTag(&mesh->htab,pt->v[i1],pt->v[i2],pt->edg[i],pt->tag[i]);
1155 if ( !ier ) {
1156 /* The edge is marked as non manifold but doesn't exist in the mesh */
1157 ier = MMG5_hEdge(mesh,&mesh->htab,pt->v[i1],pt->v[i2],pt->edg[i],pt->tag[i]);
1158 if ( !ier )
1159 return 0;
1160 }
1161 }
1162 MMG5_hGet(&mesh->htab,pt->v[i1],pt->v[i2],&edg,&tag);
1163 pt->edg[i] = edg;
1164
1165 /* If we use the nosurf option and the edge is required, we don't want
1166 * to detect it as an edge whose tag has been modified for the option */
1167 if ( mesh->info.nosurf && (tag & MG_REQ) )
1168 pt->tag[i] &= ~MG_NOSURF;
1169
1170 /* Store the edge tag inside the triangle */
1171 pt->tag[i] |= tag;
1172
1173 MMG5_hTag(&mesh->htab,pt->v[i1],pt->v[i2],edg,pt->tag[i]);
1174 }
1175 }
1177 mesh->na = 0;
1178 }
1179 /* else, infer special edges from information carried by triangles */
1180 else {
1181 if ( !mesh->adjt ) {
1182 memset(&hash,0x0,sizeof(MMG5_Hash));
1183 ier = MMG3D_hashTria(mesh,&hash);
1184 MMG5_DEL_MEM(mesh,hash.item);
1185 if ( !ier ) return 0;
1186 }
1187
1188 for (k=1; k<=mesh->nt; k++) {
1189 pt = &mesh->tria[k];
1190 adja = &mesh->adjt[3*(k-1)+1];
1191 for (i=0; i<3; i++) {
1192 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
1193 kk = adja[i] / 3;
1194 if ( !kk || pt->tag[i] & MG_NOM )
1195 mesh->na++;
1196 else if ( (k < kk) && ( pt->edg[i] || pt->tag[i] ) ) mesh->na++;
1197 }
1198 }
1199
1200 if ( mesh->htab.geom )
1202
1203 mesh->namax = MG_MAX((MMG5_int)(1.5*mesh->na),MMG3D_NAMAX);
1204 if ( !MMG5_hNew(mesh,&mesh->htab,mesh->na,3*mesh->namax) )
1205 return 0;
1206
1207 mesh->na = 0;
1208
1209 /* build hash for edges */
1210 for (k=1; k<=mesh->nt; k++) {
1211 pt = &mesh->tria[k];
1212 adja = &mesh->adjt[3*(k-1)+1];
1213 for (i=0; i<3; i++) {
1214 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
1215 i1 = MMG5_inxt2[i];
1216 i2 = MMG5_iprv2[i];
1217 kk = adja[i] / 3;
1218 if ( (!kk) || pt->tag[i] & MG_NOM ) {
1219 if ( pt->tag[i] & MG_NOM ) {
1220 if ( mesh->info.iso )
1221 pt->edg[i] = ( pt->edg[i] != 0 ) ? -MMG5_abs(pt->edg[i]) : mesh->info.isoref;
1222 }
1223 if ( !MMG5_hEdge(mesh,&mesh->htab,pt->v[i1],pt->v[i2],pt->edg[i],pt->tag[i]) )
1224 return 0;
1225 }
1226 else if ( k < kk && ( pt->edg[i] || pt->tag[i] ) ) {
1227 if ( !MMG5_hEdge(mesh,&mesh->htab,pt->v[i1],pt->v[i2],pt->edg[i],pt->tag[i]))
1228 return 0;
1229 }
1230 }
1231 }
1232 /* now check triangles */
1233 for (k=1; k<=mesh->nt; k++) {
1234 pt = &mesh->tria[k];
1235 for (i=0; i<3; i++) {
1236 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
1237 i1 = MMG5_inxt2[i];
1238 i2 = MMG5_iprv2[i];
1239 MMG5_hGet(&mesh->htab,pt->v[i1],pt->v[i2],&edg,&tag);
1240 pt->edg[i] = edg;
1241 pt->tag[i] |= tag;
1242 }
1243 }
1244 }
1245 return 1;
1246}
1247
1265static inline
1266int MMG5_bdryTria(MMG5_pMesh mesh, MMG5_int ntmesh) {
1267 MMG5_pTetra pt,pt1;
1268 MMG5_pPrism pp;
1269 MMG5_pTria ptt;
1270 MMG5_pPoint ppt;
1271 MMG5_pxTetra pxt;
1272 MMG5_pxPrism pxpr;
1273 MMG5_Hash hash;
1274 MMG5_int ref,*adja,adj,k,ia,ib,ic,kt,ntinit;
1275 int tofree=0;
1276 int8_t i,j;
1277
1278 hash.item = NULL;
1279
1280 ntinit = mesh->nt;
1281
1282 if ( mesh->nprism && (ntmesh!=ntinit) ) {
1283 /* If a triangle at the interface between a prism and a tetra is not
1284 * provided, the hash table is used to recover from the prism a boundary tria
1285 * created by tetra */
1286 if ( ! MMG5_hashNew(mesh,&hash,0.51*ntmesh,1.51*ntmesh) ) return 0;
1287 tofree=1;
1288 }
1289 else if ( mesh->nt ) {
1290 /* Hash given bdry triangles */
1291 if ( ! MMG5_hashNew(mesh,&hash,(MMG5_int)(0.51*mesh->nt),(MMG5_int)(1.51*mesh->nt)) ) return 0;
1292 tofree=1;
1293 }
1294
1295 for (k=1; k<=mesh->nt; k++) {
1296 ptt = &mesh->tria[k];
1297 if ( !MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k) ) {
1298 MMG5_DEL_MEM(mesh,hash.item);
1299 return 0;
1300 }
1301 for (i=0; i<3; i++) {
1302 ppt = &mesh->point[ptt->v[i]];
1303 if ( !mesh->info.iso ) ppt->tag |= MG_BDY;
1304 }
1305 }
1306
1307 /* Add boundary triangles stored on tetra */
1308 if ( ntmesh != ntinit ) {
1309 for (k=1; k<=mesh->ne; k++) {
1310 pt = &mesh->tetra[k];
1311 if ( !MG_EOK(pt) ) continue;
1312 adja = &mesh->adja[4*(k-1)+1];
1313 pxt = 0;
1314 if ( pt->xt ) pxt = &mesh->xtetra[pt->xt];
1315 for (i=0; i<4; i++) {
1316 adj = adja[i] / 4;
1317 pt1 = &mesh->tetra[adj];
1318
1319 if ( (!mesh->info.opnbdy) || (!mesh->xtetra) ) {
1320 /* Classic mode (no open bdy) or no info stored in xtetra (first
1321 * call) */
1322 if ( adj && ( pt->ref <= pt1->ref) ) continue;
1323 } else {
1324 /* info stored in xtetra and opnbdy mode */
1325 if ( adj && ( (pt->ref<pt1->ref) || (!pt->xt) ||
1326 (!(pxt->ftag[i] & MG_BDY)) || (!MG_GET(pxt->ori,i) ) ) )
1327 continue;
1328 }
1329
1330 ia = pt->v[MMG5_idir[i][0]];
1331 ib = pt->v[MMG5_idir[i][1]];
1332 ic = pt->v[MMG5_idir[i][2]];
1333
1334 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1335 if ( kt ) {
1336 /* Face is already stored */
1337 continue;
1338 }
1339 else if ( mesh->nprism ) {
1340 /* Update the list of boundary trias to be able to recover tria at the
1341 * interface between tet and prisms */
1342 if ( !MMG5_hashFace(mesh,&hash,ia,ib,ic,mesh->nt+1) ) {
1343 MMG5_DEL_MEM(mesh,hash.item);
1344 return 0;
1345 }
1346 }
1347
1348 /* face does not exists: add it in tria array */
1349 mesh->nt++;
1350 ptt = &mesh->tria[mesh->nt];
1351 ptt->v[0] = pt->v[MMG5_idir[i][0]];
1352 mesh->point[ptt->v[0]].tag |= MG_BDY;
1353 ptt->v[1] = pt->v[MMG5_idir[i][1]];
1354 mesh->point[ptt->v[1]].tag |= MG_BDY;
1355 ptt->v[2] = pt->v[MMG5_idir[i][2]];
1356 mesh->point[ptt->v[2]].tag |= MG_BDY;
1357
1358 /* the cc field is used to be able to recover the tetra (and its face)
1359 * from which comes a boundary triangle (when called by packmesh =>
1360 * mesh->nt=0 at the beginning of the function) */
1361 ptt->cc = 4*k + i;
1362
1363 /* If in LS mode, in analysis after ls discretization: xtetra exists. It has been created by MMG5_bdrySet */
1364 if ( pxt ) {
1365 /* Useful only when saving mesh or in ls mode */
1366 for( j = 0; j < 3; j++ ) {
1367 /* Assign tags to tria from xtetra->tag and remove redundant boundary tag:
1368 when called from ParMmg in ls mode, it is needed to remove the parallel tags
1369 coming from previous surface analysis to ensure the suitable setting of the
1370 MG_BDY tag along edges at the intersection between geometrical (true)
1371 boundaries and purely parallel interfaces. For that, it is mandatory to
1372 remove the MG_PARBDYBDY tag already added along such edges
1373 (see the step 2 of the mmgHashTria implementation) */
1374 if ( pxt->tag[MMG5_iarf[i][j]] ) {
1375 ptt->tag[j] = pxt->tag[MMG5_iarf[i][j]];
1376 /* MG_BDY is removed because by definition a triangle is on the boundary */
1377 ptt->tag[j] &= ~MG_BDY;
1378 /* MG_PARBDYBDY is removed because it will be handled properly by MMG5_mmgHashTria */
1379 ptt->tag[j] &= ~MG_PARBDYBDY;
1380 /* If the face from which we arrive is not a parallel face, then remove also the parallel tags
1381 MG_PARBDY, MG_NOSURF and MG_REQ */
1382 if ( !(pxt->ftag[i] & MG_PARBDY)) {
1383 /* Remove the tags only if the edge is identified as parallel.
1384 By convention in ParMmg (see tag_pmmg.c in ParMmg), if an entity is
1385 - parallel + not required: the tags are MG_PARBDY+MG_NOSURF+MG_REQ
1386 - parallel + truly required by the user: the tags are MG_PARBDY+MG_REQ
1387 so we remove the tags MG_NOSURF and MG_REQ only if the edge is identified as MG_NOSURF */
1388 if ( ptt->tag[j] & MG_PARBDY ) {
1389 ptt->tag[j] &= ~MG_PARBDY;
1390 /* a truly required entity does not have MG_NOSURF tag so don't remove MG_REQ tag */
1391 /* if MG_NOSURF tag, then also remove MG_REQ and MG_SURF tags */
1392 if( ptt->tag[j] & MG_NOSURF ) {
1393 ptt->tag[j] &= ~MG_NOSURF;
1394 ptt->tag[j] &= ~MG_REQ;
1395 }
1396 }
1397 }
1398 }
1399
1400 /* Assign ref to tria from xtetra->edg */
1401 if ( pxt->edg[MMG5_iarf[i][j]] )
1402 ptt->edg[j] = pxt->edg[MMG5_iarf[i][j]];
1403 }
1404 }
1405
1406 if ( adj ) {
1407 if ( mesh->info.iso ) {
1408 /* Triangle at the interface between two tets is set to the user-defined ref if any, or else to mesh->info.isoref ref */
1409 if ( pxt && pxt->ftag[i] & MG_BDY )
1410 ptt->ref = pxt->ref[i];
1411 else if( MMG5_isLevelSet(mesh,pt->ref,pt1->ref) )
1412 ptt->ref = mesh->info.isoref;
1413 else
1414 ptt->ref = MG_MIN(pt->ref,pt1->ref);
1415 }
1416 /* useful only when saving mesh or in ls mode */
1417 else {
1418 /* Triangle at the interface between two tet is set its init ref or
1419 * to the min ref of the adja tetra */
1420 ptt->ref = pxt ? pxt->ref[i] : MG_MIN(pt->ref,pt1->ref);
1421 }
1422 }
1423 else {
1424 /* useful only when saving mesh */
1425 ptt->ref = pxt ? pxt->ref[i] : pt->ref;
1426 }
1427 }
1428 }
1429 }
1430
1431 /* Add boundary triangles stored on prisms */
1432 if ( mesh->nprism ) {
1433 for (k=1; k<=mesh->nprism; k++) {
1434 pp = &mesh->prism[k];
1435 if ( !MG_EOK(pp) ) continue;
1436
1437 adja = &mesh->adjapr[5*(k-1)+1];
1438 pxpr = 0;
1439 if ( pp->xpr ) pxpr = &mesh->xprism[pp->xpr];
1440
1441 for (i=0; i<2; i++) {
1442 adj = adja[i]/5;
1443
1444
1445 if ( adj < 0 ) {
1446 if ( !mesh->nt ) continue;
1447
1448 /* Tria at the interface of a prism and a tetra: mark it as required */
1449 ia = pp->v[0+i*3];
1450 ib = pp->v[1+i*3];
1451 ic = pp->v[2+i*3];
1452
1453 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1454 if ( !kt ) continue;
1455
1456 ptt = &mesh->tria[kt];
1457
1458 if ( !(ptt->tag[0] & MG_REQ) ) {
1459 ptt->tag[0] |= MG_REQ;
1460 ptt->tag[0] |= MG_NOSURF;
1461 }
1462 if ( !(ptt->tag[1] & MG_REQ) ) {
1463 ptt->tag[1] |= MG_REQ;
1464 ptt->tag[1] |= MG_NOSURF;
1465 }
1466 if ( !(ptt->tag[2] & MG_REQ) ) {
1467 ptt->tag[2] |= MG_REQ;
1468 ptt->tag[2] |= MG_NOSURF;
1469 }
1470
1471 continue;
1472 }
1473
1474 ref = mesh->prism[adj].ref;
1475 if ( adj && ( pp->ref <= ref) ) continue;
1476
1477 ia = pp->v[0+i*3];
1478 ib = pp->v[1+i*3];
1479 ic = pp->v[2+i*3];
1480
1481 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1482 if ( kt ) {
1483 continue;
1484 }
1485
1486 mesh->nt++;
1487
1488 ptt = &mesh->tria[mesh->nt];
1489 ptt->v[0] = ia;
1490 ptt->v[1] = ib;
1491 ptt->v[2] = ic;
1492 mesh->point[ptt->v[0]].tag |= MG_BDY;
1493 mesh->point[ptt->v[1]].tag |= MG_BDY;
1494 mesh->point[ptt->v[2]].tag |= MG_BDY;
1495
1496 /* the cc field is used to be able to recover the prism (and its face)
1497 * from which comes a boundary triangle (when called by packmesh =>
1498 * mesh->nt=0 at the beginning of the function) */
1499 ptt->cc = 5*k + i;
1500 if ( pxpr ) {
1501 /* useful only when saving mesh */
1502 if ( pxpr->tag[MMG5_iarf_pr[i][0]] ) ptt->tag[0] = pxpr->tag[MMG5_iarf_pr[i][0]];
1503 if ( pxpr->tag[MMG5_iarf_pr[i][1]] ) ptt->tag[1] = pxpr->tag[MMG5_iarf_pr[i][1]];
1504 if ( pxpr->tag[MMG5_iarf_pr[i][2]] ) ptt->tag[2] = pxpr->tag[MMG5_iarf_pr[i][2]];
1505 }
1506 if ( adj ) {
1507 if ( mesh->info.iso ) ptt->ref = mesh->info.isoref;
1508 /* useful only when saving mesh */
1509 else ptt->ref = pxpr ? pxpr->ref[i] : 0;
1510 }
1511 else {
1512 /* useful only when saving mesh */
1513 ptt->ref = pxpr ? pxpr->ref[i] : 0;
1514 }
1515 }
1516 }
1517 }
1518
1519 assert(mesh->nt==ntmesh);
1520
1521 if ( ntmesh != ntinit ) {
1522 /* set point tag */
1523 for (k=1; k<=mesh->nt; k++) {
1524 ptt = &mesh->tria[k];
1525 for (i=0; i<3; i++) {
1526 ppt = &mesh->point[ptt->v[i]];
1527 ppt->tag |= MG_BDY;
1528 }
1529 }
1530 }
1531
1532 if ( tofree ) MMG5_DEL_MEM(mesh,hash.item);
1533
1534 return 1;
1535}
1536
1560 MMG5_int ntmesh,ntpres;
1561 int ier;
1562 MMG5_Hash hashElt;
1563
1565 ier = MMG5_chkBdryTria_countBoundaries(mesh,&ntmesh,&ntpres);
1566
1569 if ( mesh->nt ) {
1570 ier = MMG5_chkBdryTria_hashBoundaries(mesh,ntmesh,&hashElt);
1571 // Travel through the tria, flag those that are not in the hash tab or
1572 // that are stored more that once.
1573 ier = MMG5_chkBdryTria_flagExtraTriangles(mesh,&ntpres,&hashElt);
1574 // Delete flagged triangles
1576 }
1577 ntmesh +=ntpres;
1578
1582
1583 return 1;
1584}
1585
1595int MMG5_chkBdryTria_countBoundaries(MMG5_pMesh mesh, MMG5_int *ntmesh, MMG5_int *ntpres) {
1596
1597 MMG5_pTetra pt, pt1;
1598 MMG5_pPrism pp, pp1;
1599 MMG5_int *adja,adj,k;
1600 MMG5_int ia,ib,ic,j;
1601 MMG5_Hash hashTri;
1602 int i;
1603
1604 *ntmesh = *ntpres = 0;
1605 for (k=1; k<=mesh->ne; k++) {
1606 pt = &mesh->tetra[k];
1607 if ( !MG_EOK(pt) ) continue;
1608 adja = &mesh->adja[4*(k-1)+1];
1609 for (i=0; i<4; i++) {
1610 adj = adja[i];
1611
1612 if ( !adj ) {
1613 ++(*ntmesh);
1614 continue;
1615 }
1616 adj /= 4;
1617 pt1 = &mesh->tetra[adj];
1618 if ( pt->ref > pt1->ref )
1619 ++(*ntmesh);
1620 }
1621 }
1622
1623 if ( mesh->info.opnbdy && mesh->xtetra ) {
1624 /* We want to preserve internal triangle and we came from bdryBuild: we need
1625 * to count the preserved boudaries */
1626 for (k=1; k<=mesh->ne; k++) {
1627 pt = &mesh->tetra[k];
1628 if ( !MG_EOK(pt) || !pt->xt ) continue;
1629 adja = &mesh->adja[4*(k-1)+1];
1630 for (i=0; i<4; i++) {
1631 adj = adja[i];
1632
1633 if ( !adj ) continue;
1634
1635 adj /= 4;
1636 pt1 = &mesh->tetra[adj];
1637
1638 if ( pt->ref != pt1->ref ) continue;
1639
1640 if ( (mesh->xtetra[pt->xt].ftag[i] & MG_BDY) &&
1641 (MG_GET(mesh->xtetra[pt->xt].ori,i) ) ) ++(*ntpres);
1642 }
1643 }
1644 }
1645
1646 if ( mesh->nprism ) {
1647 for (k=1; k<=mesh->nprism; k++) {
1648 pp = &mesh->prism[k];
1649 if ( !MG_EOK(pp) ) continue;
1650
1651 adja = &mesh->adjapr[5*(k-1)+1];
1652 for (i=0; i<2; i++) {
1653 adj = adja[i];
1654
1655 if ( !adj ) {
1656 ++(*ntmesh);
1657 continue;
1658 }
1659 else if ( adj<0 ) {
1660 continue;
1661 }
1662
1663 adj /= 5;
1664 pp1 = &mesh->prism[adj];
1665 if ( pp->ref > pp1->ref) {
1666 ++(*ntmesh);
1667 }
1668 }
1669 }
1670
1671 /* Detect the triangles at the interface of the prisms and tetra (they have been
1672 * counted twice) */
1673 if ( ! MMG5_hashNew(mesh,&hashTri,0.51*(*ntmesh),1.51*(*ntmesh)) ) return 0;
1674 for (k=1; k<=mesh->ne; k++) {
1675 pt = &mesh->tetra[k];
1676 if ( !MG_EOK(pt) ) continue;
1677
1678 adja = &mesh->adja[4*(k-1)+1];
1679 for (i=0; i<4; i++) {
1680 adj = adja[i];
1681 if ( adj ) continue;
1682
1683 ia = pt->v[MMG5_idir[i][0]];
1684 ib = pt->v[MMG5_idir[i][1]];
1685 ic = pt->v[MMG5_idir[i][2]];
1686 if ( !MMG5_hashFace(mesh,&hashTri,ia,ib,ic,5*k+i) ) {
1687 MMG5_DEL_MEM(mesh,hashTri.item);
1688 return 0;
1689 }
1690 }
1691 }
1692
1693 /* Fill the adjacency relationship between prisms and tetra (fill adjapr with
1694 * a negative value to mark this special faces) */
1695 for (k=1; k<=mesh->nprism; k++) {
1696 pp = &mesh->prism[k];
1697 if ( !MG_EOK(pp) ) continue;
1698
1699 adja = &mesh->adjapr[5*(k-1)+1];
1700 for (i=0; i<2; i++) {
1701 adj = adja[i];
1702 if ( adj ) continue;
1703
1704 ia = pp->v[MMG5_idir_pr[i][0]];
1705 ib = pp->v[MMG5_idir_pr[i][1]];
1706 ic = pp->v[MMG5_idir_pr[i][2]];
1707
1708 j = MMG5_hashGetFace(&hashTri,ia,ib,ic);
1709 if ( !j ) continue;
1710
1711 --(*ntmesh);
1712 adja[i] = -j;
1713 }
1714 }
1715 MMG5_DEL_MEM(mesh,hashTri.item);
1716 }
1717 return 1;
1718}
1719
1730
1731 MMG5_pTetra pt, pt1;
1732 MMG5_pPrism pp, pp1;
1733 MMG5_int *adja,adj,k;
1734 MMG5_int ia,ib,ic;
1735 int i;
1736
1737 if ( ! MMG5_hashNew(mesh,hashElt,0.51*ntmesh,1.51*ntmesh) ) return 0;
1738 // Hash the boundaries found in the mesh
1739 if ( mesh->info.opnbdy) {
1740 /* We want to keep the internal triangles: we must hash all the tetra faces */
1741 for (k=1; k<=mesh->ne; k++) {
1742 pt = &mesh->tetra[k];
1743 if ( !MG_EOK(pt) ) continue;
1744
1745 for (i=0; i<4; i++) {
1746 ia = pt->v[MMG5_idir[i][0]];
1747 ib = pt->v[MMG5_idir[i][1]];
1748 ic = pt->v[MMG5_idir[i][2]];
1749 if ( !MMG5_hashFace(mesh,hashElt,ia,ib,ic,4*k+i) ) return 0;
1750 }
1751 }
1752 } else {
1753 for (k=1; k<=mesh->ne; k++) {
1754 pt = &mesh->tetra[k];
1755 if ( !MG_EOK(pt) ) continue;
1756 adja = &mesh->adja[4*(k-1)+1];
1757 for (i=0; i<4; i++) {
1758 adj = adja[i];
1759 if ( !adj ) {
1760 ia = pt->v[MMG5_idir[i][0]];
1761 ib = pt->v[MMG5_idir[i][1]];
1762 ic = pt->v[MMG5_idir[i][2]];
1763 if ( !MMG5_hashFace(mesh,hashElt,ia,ib,ic,4*k+i) ) return 0;
1764 }
1765 adj /= 4;
1766
1767 pt1 = &mesh->tetra[adj];
1768 if ( pt->ref > pt1->ref ) {
1769 ia = pt->v[MMG5_idir[i][0]];
1770 ib = pt->v[MMG5_idir[i][1]];
1771 ic = pt->v[MMG5_idir[i][2]];
1772 if ( !MMG5_hashFace(mesh,hashElt,ia,ib,ic,4*k+i) ) return 0;
1773 }
1774 }
1775 }
1776 }
1777 for (k=1; k<=mesh->nprism; k++) {
1778 pp = &mesh->prism[k];
1779 if ( !MG_EOK(pp) ) continue;
1780 adja = &mesh->adjapr[5*(k-1)+1];
1781 for (i=0; i<2; i++) {
1782 adj = adja[i];
1783 if ( !adj ) {
1784 ia = pp->v[MMG5_idir_pr[i][0]];
1785 ib = pp->v[MMG5_idir_pr[i][1]];
1786 ic = pp->v[MMG5_idir_pr[i][2]];
1787 if ( !MMG5_hashFace(mesh,hashElt,ia,ib,ic,5*k+i) ) return 0;
1788 }
1789 else if ( adj<0 ) continue;
1790
1791 adj /= 5;
1792
1793 pp1 = &mesh->prism[MMG5_abs(adj)];
1794 if ( pp->ref > pp1->ref ) {
1795 ia = pp->v[MMG5_idir_pr[i][0]];
1796 ib = pp->v[MMG5_idir_pr[i][1]];
1797 ic = pp->v[MMG5_idir_pr[i][2]];
1798 if ( !MMG5_hashFace(mesh,hashElt,ia,ib,ic,5*k+i) ) return 0;
1799 }
1800 }
1801 }
1802 return 1;
1803}
1804
1814
1815 MMG5_pTria ptt, pttnew;
1816 MMG5_Hash hashTri;
1817 MMG5_int k, kk, i, j;
1818 MMG5_int ia, ib, ic, adj;
1819 int iface;
1820
1821 if ( ! MMG5_hashNew(mesh,&hashTri,0.51*mesh->nt,1.51*mesh->nt) ) return 0;
1822
1823 for (k=1; k<=mesh->nt; k++) {
1824 ptt = &mesh->tria[k];
1825
1826 ia = ptt->v[0];
1827 ib = ptt->v[1];
1828 ic = ptt->v[2];
1829
1830 i = MMG5_hashGetFace(hashElt,ia,ib,ic);
1831 j = MMG5_hashFace(mesh,&hashTri,ia,ib,ic,k);
1832
1833 ptt->cc = i;
1834
1835 if ( !j ) {
1836 MMG5_DEL_MEM(mesh,hashElt->item);
1837 MMG5_DEL_MEM(mesh,hashTri.item);
1838 return 0;
1839 }
1840 else if ( j > 0 ) {
1841 /* the face already exists in the tria table */
1842 ptt->v[0] = 0;
1843 continue;
1844 }
1845
1846 if ( !i ) {
1847 /* the triangle is not a boundary tri or a tri at the interface of two
1848 * subdomains with different references and the user don't ask to keep
1849 * it. */
1850 ptt->v[0] = 0;
1851 continue;
1852 }
1853
1854 if ( mesh->info.opnbdy ) {
1855 kk = i/4;
1856 iface = i%4;
1857 adj = mesh->adja[4*(kk-1)+1+iface];
1858 /* Check if we have found a triangle at the interface of 2 doms of same
1859 * ref */
1860 if ( adj && mesh->tetra[kk].ref == mesh->tetra[adj/4].ref ) {
1861 ++(*ntpres);
1862 }
1863 }
1864 }
1865 MMG5_DEL_MEM(mesh,hashElt->item);
1866 MMG5_DEL_MEM(mesh,hashTri.item);
1867 return 1;
1868}
1869
1871
1872 MMG5_pTria ptt, pttnew;
1873 MMG5_int nt, nbl, k;
1874
1875 nt = 0; nbl = 1;
1876 for (k=1; k<=mesh->nt; k++) {
1877 ptt = &mesh->tria[k];
1878
1879 if ( !MG_EOK(ptt) ) continue;
1880
1881 ++nt;
1882 if ( k!=nbl ) {
1883 pttnew = &mesh->tria[nbl];
1884 if ( permtria ) {
1885 permtria[k] = nbl;
1886 }
1887 memcpy(pttnew,ptt,sizeof(MMG5_Tria));
1888 }
1889 ++nbl;
1890 }
1891 nbl = mesh->nt-nt;
1892 if ( nbl ) {
1893 fprintf(stderr,"\n ## Warning: %s: %" MMG5_PRId " extra boundaries provided."
1894 " Ignored\n",__func__,nbl);
1895 MMG5_ADD_MEM(mesh,(-nbl)*sizeof(MMG5_Tria),"triangles",return 0);
1896 MMG5_SAFE_REALLOC(mesh->tria,mesh->nt+1,nt+1,MMG5_Tria,"triangles",return 0);
1897 mesh->nt = nt;
1898 }
1899 return 1;
1900}
1901
1910int MMG5_chkBdryTria_addMissingTriangles(MMG5_pMesh mesh, MMG5_int ntmesh, MMG5_int ntpres) {
1911
1912 MMG5_pTria ptt;
1913 MMG5_int k, nbl;
1914 int i;
1915
1916 if ( ntpres && (mesh->info.imprim > 5 || mesh->info.ddebug) )
1917 printf(" %" MMG5_PRId " triangles between 2 tetrahdra with same"
1918 " references\n",ntpres);
1919
1920 if ( mesh->nt==ntmesh && !mesh->nprism ) {
1921 for (k=1; k<=mesh->nt; k++) {
1922 ptt = &mesh->tria[k];
1923 for (i=0; i<3; i++) {
1924 mesh->point[ptt->v[i]].tag |= MG_BDY;
1925 }
1926 }
1927 return 1;
1928 }
1929
1930 nbl = 0;
1931 if ( !mesh->nt ) {
1932 MMG5_ADD_MEM(mesh,(ntmesh+1)*sizeof(MMG5_Tria),"triangles",return 0);
1933 MMG5_SAFE_CALLOC(mesh->tria,ntmesh+1,MMG5_Tria,return 0);
1934 }
1935 else {
1936 assert((!mesh->nprism && ntmesh>mesh->nt)||(mesh->nprism && ntmesh>=mesh->nt));
1937 if ( ntmesh > mesh->nt ) {
1938 MMG5_ADD_MEM(mesh,(ntmesh-mesh->nt)*sizeof(MMG5_Tria),"triangles",return 0);
1939 MMG5_SAFE_RECALLOC(mesh->tria,mesh->nt+1,ntmesh+1,MMG5_Tria,"triangles",return 0);
1940 nbl = ntmesh-mesh->nt;
1941 }
1942 }
1943 if ( nbl && (mesh->info.imprim > 5 || mesh->info.ddebug) )
1944 fprintf(stderr,"\n ## Warning: %s: %" MMG5_PRId " extra boundaries founded\n",
1945 __func__,nbl);
1946
1947 /* Fill missing bdy triangles */
1948 return MMG5_bdryTria(mesh,ntmesh);
1949}
1950
1959 MMG5_pTetra pt,pt1;
1960 MMG5_pPrism pp;
1961 MMG5_pTria ptt;
1962 MMG5_pxTetra pxt;
1963 MMG5_pxPrism pxp;
1964 MMG5_Hash hash;
1965 MMG5_int ref,*adja,adj,k,ia,ib,ic,kt,initedg[3];
1966 int j;
1967 uint16_t tag,inittag[3];
1968 int8_t i,i1,i2;
1969
1970 if ( !mesh->nt ) return 1;
1971
1972 if ( mesh->xtetra ) {
1973 if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) {
1974 fprintf(stderr,"\n ## Error: %s: mesh->xtetra must be freed.\n",__func__);
1975 }
1976 return 0;
1977 }
1978 if ( mesh->xprism ) {
1979 if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) {
1980 fprintf(stderr,"\n ## Error: %s: mesh->xprism must be freed.\n",__func__);
1981 }
1982 return 0;
1983 }
1984
1985 if ( ! MMG5_hashNew(mesh,&hash,0.51*mesh->nt,1.51*mesh->nt) ) return 0;
1986 for (k=1; k<=mesh->nt; k++) {
1987 ptt = &mesh->tria[k];
1988 if ( !MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k) ) return 0;
1989 }
1990
1991 mesh->xt = 0;
1992 mesh->xtmax = mesh->ntmax;
1993 assert(mesh->xtmax);
1994
1995 MMG5_ADD_MEM(mesh,(mesh->xtmax+1)*sizeof(MMG5_xTetra),"boundary tetrahedra",
1996 fprintf(stderr," Exit program.\n");
1997 return 0);
1999
2000 /* assign references to tetras faces */
2001 if ( !mesh->info.opnbdy ) {
2002 for (k=1; k<=mesh->ne; k++) {
2003 pt = &mesh->tetra[k];
2004 if ( !MG_EOK(pt) ) continue;
2005 if (pt->tag & MG_OVERLAP) continue;
2006 adja = &mesh->adja[4*(k-1)+1];
2007 for (i=0; i<4; i++) {
2008 adj = adja[i] / 4;
2009 pt1 = &mesh->tetra[adj];
2010 if ( !adj || ( pt->ref != pt1->ref) ) {
2011 ia = pt->v[MMG5_idir[i][0]];
2012 ib = pt->v[MMG5_idir[i][1]];
2013 ic = pt->v[MMG5_idir[i][2]];
2014 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2015 assert(kt);
2016 if ( !pt->xt ) {
2017 mesh->xt++;
2018 if ( mesh->xt > mesh->xtmax ) {
2020 "larger xtetra table",
2021 mesh->xt--;
2022 fprintf(stderr," Exit program.\n");return 0;);
2023 }
2024 pt->xt = mesh->xt;
2025 }
2026 ptt = &mesh->tria[kt];
2027 pxt = &mesh->xtetra[pt->xt];
2028 pxt->ref[i] = ptt->ref;
2029 pxt->ftag[i] |= MG_BDY;
2030
2031 /* Store tags that are common to the 3 edges of the triangles */
2032 tag = (ptt->tag[0] & ptt->tag[1] & ptt->tag[2]);
2033
2034 /* Remove infos that make no sense along faces */
2035 tag &= ~MG_GEO;
2036 tag &= ~MG_NOM;
2037 assert( !(tag & MG_CRN) && "MG_CRN tag has no sense along edges" );
2038
2039 /* Assign tag to the face */
2040 pxt->ftag[i] |= tag;
2041 }
2042 }
2043 }
2044 }
2045 else {
2046 /* Internal triangles preservations */
2047 for (k=1; k<=mesh->ne; k++) {
2048 pt = &mesh->tetra[k];
2049 if ( !MG_EOK(pt) ) continue;
2050 if (pt->tag & MG_OVERLAP) continue;
2051
2052 for (i=0; i<4; i++) {
2053 ia = pt->v[MMG5_idir[i][0]];
2054 ib = pt->v[MMG5_idir[i][1]];
2055 ic = pt->v[MMG5_idir[i][2]];
2056 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2057
2058 if ( !kt ) continue;
2059
2060 if ( !pt->xt ) {
2061 mesh->xt++;
2062 if ( mesh->xt > mesh->xtmax ) {
2064 "larger xtetra table",
2065 mesh->xt--;
2066 fprintf(stderr," Exit program.\n");return 0;);
2067 }
2068 pt->xt = mesh->xt;
2069 }
2070 ptt = &mesh->tria[kt];
2071 pxt = &mesh->xtetra[mesh->xt];
2072 pxt->ref[i] = ptt->ref;
2073 pxt->ftag[i] |= MG_BDY;
2074
2075 /* here we may wrongfully add MG_REF and/or MG_BDY face tags to internal triangles
2076 in opnbdy mode */
2077 /* Store tags that are common to the 3 edges of the triangles */
2078 tag = (ptt->tag[0] & ptt->tag[1] & ptt->tag[2]);
2079
2080 /* Remove infos that make no sense along faces */
2081 tag &= ~MG_GEO;
2082 tag &= ~MG_NOM;
2083 assert( !(tag & MG_CRN) && "MG_CRN tag has no sense along edges" );
2084
2085 /* Assign tag to the face */
2086 pxt->ftag[i] |= tag;
2087 }
2088 }
2089 }
2090
2091 if ( !mesh->info.opnbdy ) {
2092 for (k=1; k<=mesh->ne; k++) {
2093 pt = &mesh->tetra[k];
2094 if ( !MG_EOK(pt) ) continue;
2095 if (pt->tag & MG_OVERLAP) continue;
2096 if ( !pt->xt ) continue;
2097 pxt = &mesh->xtetra[pt->xt];
2098 adja = &mesh->adja[4*(k-1)+1];
2099 for (i=0; i<4; i++) {
2100 adj = adja[i] / 4;
2101 pt1 = &mesh->tetra[adj];
2102 /* Set edge tag */
2103 if ( pxt->ftag[i] ) {
2104 if ( adj && (pt->ref == pt1->ref ) ) {
2105 continue;
2106 }
2107 else {
2108 ia = pt->v[MMG5_idir[i][0]];
2109 ib = pt->v[MMG5_idir[i][1]];
2110 ic = pt->v[MMG5_idir[i][2]];
2111 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2112 ptt = &mesh->tria[kt];
2113
2114 /* Set flag to know if tetra has the same orientation than the
2115 * triangle */
2116 if ( ptt->v[0] == ia && ptt->v[1] == ib && ptt->v[2] == ic ) {
2117 MG_SET(pxt->ori,i);
2118 for (j=0; j<3; j++) {
2119 tag = pxt->ftag[i] | ptt->tag[j];
2120 if ( tag ) {
2121 if ( !MMG5_settag(mesh,k,MMG5_iarf[i][j],tag,ptt->edg[j]) )
2122 return 0;
2123 }
2124 }
2125 }
2126 else
2127 MG_CLR(pxt->ori,i);
2128 }
2129 }
2130 }
2131 }
2132 }
2133 else {
2134 for (k=1; k<=mesh->ne; k++) {
2135 pt = &mesh->tetra[k];
2136 if ( !MG_EOK(pt) ) continue;
2137 if (pt->tag & MG_OVERLAP) continue;
2138 if ( !pt->xt ) continue;
2139 pxt = &mesh->xtetra[pt->xt];
2140 adja = &mesh->adja[4*(k-1)+1];
2141 for (i=0; i<4; i++) {
2142 adj = adja[i] / 4;
2143 pt1 = &mesh->tetra[adj];
2144
2145 ia = pt->v[MMG5_idir[i][0]];
2146 ib = pt->v[MMG5_idir[i][1]];
2147 ic = pt->v[MMG5_idir[i][2]];
2148 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2149
2150 if ( !kt ) continue;
2151
2152 ptt = &mesh->tria[kt];
2153
2154 /* Set flag to know if tetra has the same orientation than the triangle
2155 * + force the triangle numbering to match the tetra face numbering */
2156 if ( adj ) {
2157 for ( j=0; j<3; ++j ) {
2158 i1 = MMG5_inxt2[j];
2159 i2 = MMG5_inxt2[i1];
2160 if ( ptt->v[j]==ia && ptt->v[i1]==ib && ptt->v[i2]==ic )
2161 break;
2162 }
2163 if ( j<3 ) {
2164 MG_SET(pxt->ori,i);
2165 if ( j!=0 ) {
2166 /* Triangle vertices+tag/edg reordering */
2167 ptt->v[0] = ia;
2168 ptt->v[1] = ib;
2169 ptt->v[2] = ic;
2170
2171 inittag[0] = ptt->tag[0];
2172 inittag[1] = ptt->tag[1];
2173 inittag[2] = ptt->tag[2];
2174 ptt->tag[0] = inittag[j];
2175 ptt->tag[1] = inittag[i1];
2176 ptt->tag[2] = inittag[i2];
2177
2178 initedg[0] = ptt->edg[0];
2179 initedg[1] = ptt->edg[1];
2180 initedg[2] = ptt->edg[2];
2181 ptt->edg[0] = initedg[j];
2182 ptt->edg[1] = initedg[i1];
2183 ptt->edg[2] = initedg[i2];
2184 }
2185 }
2186 else {
2187 MG_CLR(pxt->ori,i);
2188 }
2189 }
2190 else MG_SET(pxt->ori,i);
2191
2192 /* Set edge tag */
2193 if ( pxt->ftag[i] ) {
2194 if ( adj && ( (pt->ref < pt1->ref) || !MG_GET(pxt->ori,i) ) ) {
2195 continue;
2196 }
2197 else {
2198 for (j=0; j<3; j++) {
2199 tag = pxt->ftag[i] | ptt->tag[j];
2200 if ( tag ) {
2201 if ( !MMG5_settag(mesh,k,MMG5_iarf[i][j],tag,ptt->edg[j]) )
2202 return 0;
2203 }
2204 }
2205 }
2206 }
2207 }
2208 }
2209 }
2210
2211 if ( !mesh->nprism ) {
2212 MMG5_DEL_MEM(mesh,hash.item);
2213 return 1;
2214 }
2215
2216 mesh->xpr = 0;
2217 MMG5_ADD_MEM(mesh,(mesh->nprism+1)*sizeof(MMG5_xPrism),"boundary prisms",
2218 fprintf(stderr," Exit program.\n");
2219 return 0);
2221
2222 /* assign references to prism faces */
2223 for (k=1; k<=mesh->nprism; k++) {
2224 pp = &mesh->prism[k];
2225 if ( !MG_EOK(pp) ) continue;
2226 adja = &mesh->adjapr[5*(k-1)+1];
2227 for (i=0; i<2; i++) {
2228 adj = adja[i] / 5;
2229 if ( adj<0 ) {
2230 ref = mesh->tetra[MMG5_abs(adj)].ref;
2231 } else {
2232 ref = mesh->prism[adj].ref;
2233 }
2234 if ( adj && (pp->ref == ref) ) continue;
2235
2236 ia = pp->v[MMG5_idir_pr[i][0]];
2237 ib = pp->v[MMG5_idir_pr[i][1]];
2238 ic = pp->v[MMG5_idir_pr[i][2]];
2239 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2240 assert(kt);
2241 if ( !pp->xpr ) {
2242 mesh->xpr++;
2243 pp->xpr = mesh->xpr;
2244 }
2245 ptt = &mesh->tria[kt];
2246 pxp = &mesh->xprism[mesh->xpr];
2247 pxp->ref[i] = ptt->ref;
2248 pxp->ftag[i] |= MG_BDY;
2249
2250 /* Store tags that are common to the 3 edges of the triangles */
2251 tag = (ptt->tag[0] & ptt->tag[1] & ptt->tag[2]);
2252
2253 /* Remove infos that make no sense along faces */
2254 tag &= ~MG_GEO;
2255 tag &= ~MG_NOM;
2256 assert( !(tag & MG_CRN) && "MG_CRN tag has no sense along edges" );
2257
2258 /* Assign tag to the face */
2259 pxp->ftag[i] |= tag;
2260
2261 for (j=0; j<3; j++) {
2262 pxp->tag[MMG5_iarf[i][j]] |= pxp->ftag[i] | ptt->tag[j];
2263 pxp->edg[MMG5_iarf[i][j]] = ptt->edg[j];
2264 }
2265 }
2266 }
2267 MMG5_ADD_MEM(mesh,(mesh->xpr-mesh->nprism)*sizeof(MMG5_xPrism),"boundary prisms",
2268 fprintf(stderr," Exit program.\n");
2269 return 0);
2271 "boundary prisms",return 0);
2272
2273 MMG5_DEL_MEM(mesh,hash.item);
2274 return 1;
2275}
2276
2295 MMG5_pTetra pt;
2296 MMG5_pTria ptt;
2297 MMG5_pxTetra pxt;
2298 MMG5_Hash hash;
2299 MMG5_int ia,ib,ic,k,kt;
2300 int j;
2301 uint16_t tag;
2302 int8_t i;
2303
2304 if ( !mesh->nt ) return 1;
2305 if ( !MMG5_hashNew(mesh,&hash,0.51*mesh->nt,1.51*mesh->nt) ) return 0;
2306 for (k=1; k<=mesh->nt; k++) {
2307 ptt = &mesh->tria[k];
2308 if ( !MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k) ) {
2309 MMG5_DEL_MEM(mesh,hash.item);
2310 return 0;
2311 }
2312 }
2313
2314 for (k=1; k<=mesh->ne; k++) {
2315 pt = &mesh->tetra[k];
2316 if ( !MG_EOK(pt) ) continue;
2317 if ( pt->tag & MG_REQ ) {
2318 mesh->point[mesh->tetra[k].v[0]].tag |= MG_REQ;
2319 mesh->point[mesh->tetra[k].v[1]].tag |= MG_REQ;
2320 mesh->point[mesh->tetra[k].v[2]].tag |= MG_REQ;
2321 mesh->point[mesh->tetra[k].v[3]].tag |= MG_REQ;
2322 if ( !MMG5_settag(mesh,k,0,MG_REQ,0) ) return 0;
2323 if ( !MMG5_settag(mesh,k,1,MG_REQ,0) ) return 0;
2324 if ( !MMG5_settag(mesh,k,2,MG_REQ,0) ) return 0;
2325 if ( !MMG5_settag(mesh,k,3,MG_REQ,0) ) return 0;
2326 if ( !MMG5_settag(mesh,k,4,MG_REQ,0) ) return 0;
2327 if ( !MMG5_settag(mesh,k,5,MG_REQ,0) ) return 0;
2328 mesh->point[mesh->tetra[k].v[0]].tag &= ~MG_NOSURF;
2329 mesh->point[mesh->tetra[k].v[1]].tag &= ~MG_NOSURF;
2330 mesh->point[mesh->tetra[k].v[2]].tag &= ~MG_NOSURF;
2331 mesh->point[mesh->tetra[k].v[3]].tag &= ~MG_NOSURF;
2332 if ( !MMG5_deltag(mesh,k,0,MG_NOSURF) ) return 0;
2333 if ( !MMG5_deltag(mesh,k,1,MG_NOSURF) ) return 0;
2334 if ( !MMG5_deltag(mesh,k,2,MG_NOSURF) ) return 0;
2335 if ( !MMG5_deltag(mesh,k,3,MG_NOSURF) ) return 0;
2336 if ( !MMG5_deltag(mesh,k,4,MG_NOSURF) ) return 0;
2337 if ( !MMG5_deltag(mesh,k,5,MG_NOSURF) ) return 0;
2338 }
2339
2340 if ( !pt->xt ) continue;
2341 pxt = &mesh->xtetra[pt->xt];
2342
2343 for (i=0; i<4; i++) {
2344 /* Set edge tag */
2345 if ( ! MG_GET(pxt->ori,i) ) continue;
2346 if ( pxt->ftag[i] & MG_BDY ) {
2347 ia = pt->v[MMG5_idir[i][0]];
2348 ib = pt->v[MMG5_idir[i][1]];
2349 ic = pt->v[MMG5_idir[i][2]];
2350 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2351 assert(kt);
2352 ptt = &mesh->tria[kt];
2353 if ( pt->tag & MG_REQ ) {
2354 pxt->ftag[i] |= MG_REQ;
2355 ptt->tag[0] = MG_REQ;
2356 ptt->tag[1] = MG_REQ;
2357 ptt->tag[2] = MG_REQ;
2358 pxt->ftag[i] &= ~MG_NOSURF;
2359 ptt->tag[0] &= ~MG_NOSURF;
2360 ptt->tag[1] &= ~MG_NOSURF;
2361 ptt->tag[2] &= ~MG_NOSURF;
2362 }
2363 for ( j=0; j<3; j++ ) {
2364 tag = ptt->tag[j];
2365 if ( tag || ptt->edg[j] ) {
2366 if ( !MMG5_settag(mesh,k,MMG5_iarf[i][j],tag,ptt->edg[j]) )
2367 return 0;
2368 }
2369 }
2370 }
2371 }
2372 }
2373 MMG5_DEL_MEM(mesh,hash.item);
2374 return 1;
2375}
2376
2386 MMG5_pTetra pt,pt1;
2387 MMG5_pTria ptt;
2388 MMG5_Hash hash;
2389 MMG5_int *adja,adj,k,kt,ia,ib,ic,nf;
2390 int8_t i;
2391
2392 if ( !mesh->nt ) return 1;
2393
2394 /* store triangles temporarily */
2395 if ( !MMG5_hashNew(mesh,&hash,MG_MAX(0.51*mesh->nt,100),MG_MAX(1.51*mesh->nt,300)) )
2396 return 0;
2397
2398 for (k=1; k<=mesh->nt; k++) {
2399 ptt = &mesh->tria[k];
2400 if ( !MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k) ) {
2401 MMG5_DEL_MEM(mesh,hash.item);
2402 return 0;
2403 }
2404 }
2405
2406 /* check orientation */
2407 nf = 0;
2408 for (k=1; k<=mesh->ne; k++) {
2409 pt = &mesh->tetra[k];
2410 if ( !MG_EOK(pt) ) continue;
2411 adja = &mesh->adja[4*(k-1)+1];
2412 for (i=0; i<4; i++) {
2413 adj = adja[i] / 4;
2414 pt1 = &mesh->tetra[adj];
2415
2416 if ( adj && (pt->ref <= pt1->ref || pt->ref == MG_PLUS) )
2417 continue;
2418
2419 ia = pt->v[MMG5_idir[i][0]];
2420 ib = pt->v[MMG5_idir[i][1]];
2421 ic = pt->v[MMG5_idir[i][2]];
2422 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2423 if ( kt ) {
2424 /* check orientation */
2425 ptt = &mesh->tria[kt];
2426 if ( ptt->v[0] == ia && ptt->v[1] == ib && ptt->v[2] == ic )
2427 continue;
2428 else {
2429 ptt->v[0] = ia;
2430 ptt->v[1] = ib;
2431 ptt->v[2] = ic;
2432 nf++;
2433 }
2434 }
2435 }
2436 }
2437 if ( mesh->info.ddebug && nf > 0 )
2438 fprintf(stdout," ## %" MMG5_PRId " faces reoriented\n",nf);
2439
2440 MMG5_DEL_MEM(mesh,hash.item);
2441
2442 return 1;
2443}
int ier
tmp[*strlen0]
if(!ier) exit(EXIT_FAILURE)
MMG5_pMesh * mesh
int MMG5_settag(MMG5_pMesh mesh, MMG5_int start, int ia, uint16_t tag, int edg)
Definition: boulep_3d.c:1234
void MMG3D_coquilFaceSecondLoopInit(MMG5_pMesh mesh, MMG5_int piv, int8_t *iface, int8_t *ia, int64_t *list, int *ilist, MMG5_int *it1, MMG5_int *pradj, MMG5_int *adj)
Definition: boulep_3d.c:1790
int MMG3D_coquilFaceFirstLoop(MMG5_pMesh mesh, MMG5_int start, MMG5_int na, MMG5_int nb, int8_t iface, int8_t ia, int64_t *list, int *ilist, MMG5_int *it1, MMG5_int *it2, MMG5_int *piv, MMG5_int *adj, int8_t *hasadja, int *nbdy, int silent)
Definition: boulep_3d.c:1689
void MMG5_coquilFaceErrorMessage(MMG5_pMesh mesh, MMG5_int k1, MMG5_int k2)
Definition: boulep_3d.c:1616
int16_t MMG5_openCoquilTravel(MMG5_pMesh mesh, MMG5_int na, MMG5_int nb, MMG5_int *adj, MMG5_int *piv, int8_t *iface, int8_t *i)
Definition: boulep_3d.c:2014
int MMG5_deltag(MMG5_pMesh mesh, MMG5_int start, int ia, uint16_t tag)
Definition: boulep_3d.c:1347
MMG5_int MMG5_hashFace(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int ia, MMG5_int ib, MMG5_int ic, MMG5_int k)
Definition: hash.c:286
int MMG5_mmgHashTria(MMG5_pMesh mesh, MMG5_int *adjt, MMG5_Hash *hash, int chkISO)
Definition: hash.c:58
int MMG5_hashNew(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int hsiz, MMG5_int hmax)
Definition: hash.c:532
int MMG5_hashEdge(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int a, MMG5_int b, MMG5_int k)
Definition: hash.c:346
int MMG5_paktet(MMG5_pMesh mesh)
Definition: hash_3d.c:50
int MMG3D_hashTetra(MMG5_pMesh mesh, int pack)
Create array of adjacency.
Definition: hash_3d.c:122
int MMG5_chkBdryTria_flagExtraTriangles(MMG5_pMesh mesh, MMG5_int *ntpres, MMG5_Hash *hashElt)
Definition: hash_3d.c:1813
int MMG5_hEdge(MMG5_pMesh mesh, MMG5_HGeom *hash, MMG5_int a, MMG5_int b, MMG5_int ref, uint16_t tag)
Definition: hash_3d.c:1040
int MMG5_hGeom(MMG5_pMesh mesh)
Definition: hash_3d.c:1111
int MMG5_hPop(MMG5_HGeom *hash, MMG5_int a, MMG5_int b, MMG5_int *ref, uint16_t *tag)
Definition: hash_3d.c:947
int MMG5_hGet(MMG5_HGeom *hash, MMG5_int a, MMG5_int b, MMG5_int *ref, uint16_t *tag)
Definition: hash_3d.c:1007
int MMG5_hNew(MMG5_pMesh mesh, MMG5_HGeom *hash, MMG5_int hsiz, MMG5_int hmax)
Definition: hash_3d.c:1083
int MMG3D_hashPrism(MMG5_pMesh mesh)
Definition: hash_3d.c:240
int MMG5_hTag(MMG5_HGeom *hash, MMG5_int a, MMG5_int b, MMG5_int ref, uint16_t tag)
Definition: hash_3d.c:914
static int MMG5_bdryTria(MMG5_pMesh mesh, MMG5_int ntmesh)
Definition: hash_3d.c:1266
MMG5_int MMG5_hashGetFace(MMG5_Hash *hash, MMG5_int ia, MMG5_int ib, MMG5_int ic)
Definition: hash_3d.c:84
static uint16_t MMG5_skip_ParBdy(uint16_t tag)
Definition: hash_3d.c:618
int MMG5_chkBdryTria_addMissingTriangles(MMG5_pMesh mesh, MMG5_int ntmesh, MMG5_int ntpres)
Definition: hash_3d.c:1910
int MMG5_chkBdryTria(MMG5_pMesh mesh)
Definition: hash_3d.c:1559
int MMG5_bdrySet(MMG5_pMesh mesh)
Definition: hash_3d.c:1958
int MMG5_chkBdryTria_hashBoundaries(MMG5_pMesh mesh, MMG5_int ntmesh, MMG5_Hash *hashElt)
Definition: hash_3d.c:1729
static int MMG5_setEdgeNmTag(MMG5_pMesh mesh, MMG5_Hash *hash)
Definition: hash_3d.c:460
int8_t ddb
Definition: mmg3d1_delone.c:42
int MMG5_bdryUpdate(MMG5_pMesh mesh)
Definition: hash_3d.c:2294
int MMG5_setNmTag(MMG5_pMesh mesh, MMG5_Hash *hash)
Definition: hash_3d.c:816
int MMG3D_hashTria(MMG5_pMesh mesh, MMG5_Hash *hash)
Definition: hash_3d.c:838
int MMG5_setVertexNmTag(MMG5_pMesh mesh, uint16_t func(uint16_t))
Definition: hash_3d.c:637
int MMG5_hashPop(MMG5_Hash *hash, MMG5_int a, MMG5_int b)
Definition: hash_3d.c:850
int MMG5_chkBdryTria_deleteExtraTriangles(MMG5_pMesh mesh, MMG5_int *permtria)
Definition: hash_3d.c:1870
int MMG5_bdryPerm(MMG5_pMesh mesh)
Definition: hash_3d.c:2385
#define MMG5_KC
Definition: hash_3d.c:38
int MMG5_chkBdryTria_countBoundaries(MMG5_pMesh mesh, MMG5_int *ntmesh, MMG5_int *ntpres)
Definition: hash_3d.c:1595
API headers and documentation for the mmg3d library, for volumetric meshes in 3D.
#define MMG3D_LMAX
Definition: libmmg3d.h:130
MMG5_int MMG3D_indPt(MMG5_pMesh mesh, MMG5_int kp)
Definition: tools_3d.c:918
int MMG3D_delElt(MMG5_pMesh mesh, MMG5_int iel)
Definition: zaldy_3d.c:122
#define MMG3D_NAMAX
static const int8_t MMG5_iarf[4][3]
iarf[i]: edges of face opposite to vertex i
static const uint8_t MMG5_iare[6][2]
vertices of extremities of the edges of the tetra
static const uint8_t MMG5_iarf_pr[5][5]
iarf[i]: edges of face i for a prism
static const uint8_t MMG5_idir_pr[5][4]
idir[i]: vertices of face i for a prism
static const uint8_t MMG5_idir[4][3]
idir[i]: vertices of face opposite to vertex i
#define MG_PLUS
Definition: libmmgtypes.h:77
int MMG5_isLevelSet(MMG5_pMesh mesh, MMG5_int ref0, MMG5_int ref1)
Definition: mmg2.c:472
#define MG_REQ
#define MG_GEO
#define MMG5_SAFE_CALLOC(ptr, size, type, law)
#define MG_EOK(pt)
#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]
#define MMG5_KB
#define MG_EDG_OR_NOM(tag)
#define MMG5_TAB_RECALLOC(mesh, ptr, initSize, wantedGap, type, message, law)
#define MG_GET(flag, bit)
static const uint8_t MMG5_inxt2[6]
#define MG_VOK(ppt)
#define MG_OVERLAP
#define MG_CRN
#define MG_BDY
#define MMG5_SAFE_MALLOC(ptr, size, type, law)
#define MG_NOSURF
#define MG_NOM
#define MMG5_KA
#define MG_REF
#define MG_PARBDYBDY
#define MMG5_SAFE_FREE(ptr)
#define MMG5_DEL_MEM(mesh, ptr)
#define MG_SET(flag, bit)
#define MMG5_SAFE_RECALLOC(ptr, prevSize, newSize, type, message, law)
Structure to store edges of am MMG mesh.
Definition: libmmgtypes.h:311
MMG5_int b
Definition: libmmgtypes.h:312
uint16_t tag
Definition: libmmgtypes.h:316
MMG5_int ref
Definition: libmmgtypes.h:313
MMG5_int a
Definition: libmmgtypes.h:312
Hash table to store geometric edges.
Definition: libmmgtypes.h:582
MMG5_int max
Definition: libmmgtypes.h:584
MMG5_hgeom * geom
Definition: libmmgtypes.h:583
MMG5_int siz
Definition: libmmgtypes.h:584
MMG5_int nxt
Definition: libmmgtypes.h:584
Identic as MMG5_HGeom but use MMG5_hedge to store edges instead of MMG5_hgeom (memory economy).
Definition: libmmgtypes.h:603
MMG5_int nxt
Definition: libmmgtypes.h:604
MMG5_hedge * item
Definition: libmmgtypes.h:605
MMG5_int siz
Definition: libmmgtypes.h:604
int8_t iso
Definition: libmmgtypes.h:541
int8_t ddebug
Definition: libmmgtypes.h:539
MMG5_int isoref
Definition: libmmgtypes.h:528
uint8_t nosurf
Definition: libmmgtypes.h:553
MMG mesh structure.
Definition: libmmgtypes.h:613
MMG5_int ntmax
Definition: libmmgtypes.h:620
MMG5_Info info
Definition: libmmgtypes.h:659
MMG5_int * adjapr
Definition: libmmgtypes.h:640
MMG5_int xt
Definition: libmmgtypes.h:628
MMG5_int ne
Definition: libmmgtypes.h:620
MMG5_pPoint point
Definition: libmmgtypes.h:649
MMG5_int xpr
Definition: libmmgtypes.h:628
MMG5_int * adja
Definition: libmmgtypes.h:632
MMG5_pPrism prism
Definition: libmmgtypes.h:653
MMG5_int xtmax
Definition: libmmgtypes.h:620
MMG5_int nemax
Definition: libmmgtypes.h:620
MMG5_int nenil
Definition: libmmgtypes.h:630
MMG5_HGeom htab
Definition: libmmgtypes.h:658
MMG5_int namax
Definition: libmmgtypes.h:620
MMG5_pTetra tetra
Definition: libmmgtypes.h:651
MMG5_pxPrism xprism
Definition: libmmgtypes.h:654
MMG5_int nt
Definition: libmmgtypes.h:620
MMG5_pTria tria
Definition: libmmgtypes.h:655
MMG5_int np
Definition: libmmgtypes.h:620
MMG5_pEdge edge
Definition: libmmgtypes.h:657
MMG5_pxTetra xtetra
Definition: libmmgtypes.h:652
MMG5_int nprism
Definition: libmmgtypes.h:621
MMG5_int na
Definition: libmmgtypes.h:620
MMG5_int * adjt
Definition: libmmgtypes.h:636
Structure to store vertices of an MMG mesh.
Definition: libmmgtypes.h:276
uint16_t tag
Definition: libmmgtypes.h:290
Structure to store prsim of a MMG mesh.
Definition: libmmgtypes.h:469
MMG5_int v[6]
Definition: libmmgtypes.h:470
MMG5_int ref
Definition: libmmgtypes.h:471
MMG5_int xpr
Definition: libmmgtypes.h:474
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 ref
Definition: libmmgtypes.h:410
uint16_t tag
Definition: libmmgtypes.h:417
Structure to store triangles of a MMG mesh.
Definition: libmmgtypes.h:338
MMG5_int edg[3]
Definition: libmmgtypes.h:345
MMG5_int ref
Definition: libmmgtypes.h:341
uint16_t tag[3]
Definition: libmmgtypes.h:348
MMG5_int v[3]
Definition: libmmgtypes.h:340
MMG5_int cc
Definition: libmmgtypes.h:343
Used to hash edges (memory economy compared to MMG5_hgeom).
Definition: libmmgtypes.h:592
MMG5_int s
Definition: libmmgtypes.h:595
MMG5_int b
Definition: libmmgtypes.h:593
MMG5_int a
Definition: libmmgtypes.h:593
MMG5_int k
Definition: libmmgtypes.h:594
MMG5_int nxt
Definition: libmmgtypes.h:593
Cell of the hash table of geometric edges.
Definition: libmmgtypes.h:570
MMG5_int ref
Definition: libmmgtypes.h:573
MMG5_int b
Definition: libmmgtypes.h:572
MMG5_int nxt
Definition: libmmgtypes.h:574
MMG5_int a
Definition: libmmgtypes.h:571
uint16_t tag
Definition: libmmgtypes.h:575
Structure to store the surface prism of a MMG mesh.
Definition: libmmgtypes.h:484
uint16_t ftag[5]
Definition: libmmgtypes.h:491
MMG5_int edg[9]
Definition: libmmgtypes.h:487
MMG5_int ref[5]
Definition: libmmgtypes.h:485
uint16_t tag[9]
Definition: libmmgtypes.h:493
Structure to store additional information for the surface tetrahedra of an MMG mesh.
Definition: libmmgtypes.h:425
uint16_t tag[6]
Definition: libmmgtypes.h:432
int8_t ori
Definition: libmmgtypes.h:434
MMG5_int edg[6]
Definition: libmmgtypes.h:428
MMG5_int ref[4]
Definition: libmmgtypes.h:426
uint16_t ftag[4]
Definition: libmmgtypes.h:430