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 if ( sizeof(MMG5_int) == 8 ) {
156 inival = LONG_MAX;
157 }
158 else {
159 inival = INT_MAX;
160 }
161
162 iadr = 0;
163 for (k=0; k<=mesh->ne; k++)
164 hcode[k] = -inival;
165
166 /* hash tetras */
167 for (k=1; k<=mesh->ne; k++) {
168 pt = &mesh->tetra[k];
169 if ( !MG_EOK(pt) ) continue;
170 for (i=0; i<4; i++) {
171 i1 = MMG5_idir[i][0];
172 i2 = MMG5_idir[i][1];
173 i3 = MMG5_idir[i][2];
174 mins = MG_MIN(pt->v[i1],MG_MIN(pt->v[i2],pt->v[i3]));
175 maxs = MG_MAX(pt->v[i1],MG_MAX(pt->v[i2],pt->v[i3]));
176
177 /* compute key and insert */
178 sum = pt->v[i1] + pt->v[i2] + pt->v[i3];
179 key = (MMG5_KA*(int64_t)mins+MMG5_KB*(int64_t)maxs+MMG5_KC*(int64_t)sum)%hsize+1;
180 iadr++;
181 link[iadr] = hcode[key];
182 hcode[key] = -iadr;
183 }
184 }
185
186 /* set adjacency */
187 if ( mesh->info.ddebug ) fprintf(stdout," h- stage 2: adjacencies\n");
188 for (l=iadr; l>0; l--) {
189 if ( link[l] >= 0 ) continue;
190
191 /* current element */
192 k = (l-1) / 4 + 1;
193 i = (l-1) % 4;
194 i1 = MMG5_idir[i][0];
195 i2 = MMG5_idir[i][1];
196 i3 = MMG5_idir[i][2];
197 pt = &mesh->tetra[k];
198 mins = MG_MIN(pt->v[i1],MG_MIN(pt->v[i2],pt->v[i3]));
199 maxs = MG_MAX(pt->v[i1],MG_MAX(pt->v[i2],pt->v[i3]));
200 sum = pt->v[i1] + pt->v[i2] + pt->v[i3];
201
202 /* accross link */
203 ll = -link[l];
204 pp = 0;
205 link[l] = 0;
206 while ( ll != inival ) {
207 kk = (ll-1) / 4 + 1;
208 ii = (ll-1) % 4;
209 i1 = MMG5_idir[ii][0];
210 i2 = MMG5_idir[ii][1];
211 i3 = MMG5_idir[ii][2];
212 pt1 = &mesh->tetra[kk];
213 sum1 = pt1->v[i1] + pt1->v[i2] + pt1->v[i3];
214 if ( sum1 == sum ) {
215 mins1 = MG_MIN(pt1->v[i1],MG_MIN(pt1->v[i2],pt1->v[i3]));
216 maxs1 = MG_MAX(pt1->v[i1],MG_MAX(pt1->v[i2],pt1->v[i3]));
217
218 /* adjacent found */
219 if ( mins1 == mins && maxs1 == maxs ) {
220 if ( pp != 0 ) link[pp] = link[ll];
221 link[l] = 4*kk + ii;
222 link[ll] = 4*k + i;
223 break;
224 }
225 }
226 pp = ll;
227 ll = -link[ll];
228 }
229 }
230 MMG5_SAFE_FREE(hcode);
231 return 1;
232}
233
246 MMG5_pPrism pp,pp1;
247 MMG5_int key;
248 MMG5_int k,kk,l,ll,jj;
249 MMG5_int max12,min12,max34,min34,mins,mins1,mins_b, mins_b1,maxs,maxs1;
250 MMG5_int iadr;
251 MMG5_int *hcode,*link,hsize,inival;
252 uint8_t i,ii,i1,i2,i3,i4;
253
254 if ( !mesh->nprism ) return 1;
255
256 /* default */
257 if ( mesh->adjapr ) {
258 if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) {
259 fprintf(stderr,"\n ## Warning: %s: no re-build of adjacencies of prisms. "
260 "mesh->adjapr must be freed to enforce analysis.\n",__func__);
261 }
262 return 1;
263 }
264
265 if ( abs(mesh->info.imprim) > 5 || mesh->info.ddebug )
266 fprintf(stdout," ** SETTING PRISMS ADJACENCY\n");
267
268 /* memory alloc */
269 MMG5_ADD_MEM(mesh,(5*mesh->nprism+6)*sizeof(MMG5_int),"prism adjacency table",
270 printf(" Exit program.\n");
271 return 0);
272 MMG5_SAFE_CALLOC(mesh->adjapr,5*mesh->nprism+6,MMG5_int,return 0);
273 MMG5_SAFE_CALLOC(hcode,mesh->nprism+6,MMG5_int,return 0);
274
275 link = mesh->adjapr;
276 hsize = mesh->nprism;
277
278 /* init */
279 if ( mesh->info.ddebug ) fprintf(stdout," h- stage 1: init\n");
280
281 if ( sizeof(MMG5_int) == 8 ) {
282 inival = LONG_MAX;
283 }
284 else {
285 inival = INT_MAX;
286 }
287
288 iadr = 0;
289 for (k=0; k<=mesh->nprism; k++)
290 hcode[k] = -inival;
291
292 /* hash prism */
293 for (k=1; k<=mesh->nprism; k++) {
294 pp = &mesh->prism[k];
295 assert ( MG_EOK(pp) );
296 for (i=0; i<2; i++) {
297 /* Triangular face */
298 i1 = MMG5_idir_pr[i][0];
299 i2 = MMG5_idir_pr[i][1];
300 i3 = MMG5_idir_pr[i][2];
301
302 min12 = MG_MIN(pp->v[i1],pp->v[i2]);
303 /* mins = minimum index of triangle vertices */
304 mins = MG_MIN(min12,pp->v[i3]);
305
306 max12 = MG_MAX(pp->v[i1],pp->v[i2]);
307 /* maxs = maximum index of triangle vertices */
308 maxs = MG_MAX(max12,pp->v[i3]);
309
310 /* mins_b = second minimum index of triangle vertices */
311 mins_b = pp->v[i1] + pp->v[i2] + pp->v[i3] -mins -maxs;
312
313 /* compute key and insert */
314 key = (MMG5_KA*(int64_t)mins+MMG5_KB*(int64_t)mins_b+MMG5_KC*(int64_t)maxs)%hsize+1;
315 iadr++;
316 link[iadr] = hcode[key];
317 hcode[key] = -iadr;
318 }
319 for ( ; i<5; ++i) {
320 /* Quadrilateral face */
321 i1 = MMG5_idir_pr[i][0];
322 i2 = MMG5_idir_pr[i][1];
323 i3 = MMG5_idir_pr[i][2];
324 i4 = MMG5_idir_pr[i][3];
325
326 min12 = MG_MIN(pp->v[i1],pp->v[i2]);
327 min34 = MG_MIN(pp->v[i3],pp->v[i4]);
328 /* mins = minimum index of quadrilateral vertices */
329 mins = MG_MIN(min12,min34);
330
331 max12 = MG_MAX(pp->v[i1],pp->v[i2]);
332 max34 = MG_MAX(pp->v[i3],pp->v[i4]);
333 /* maxs = maximum index of quadrilateral vertices */
334 maxs = MG_MAX(max12,max34);
335
336 /* mins_b = second minimum index of quadrilateral vertices */
337 mins_b = MG_MIN( MG_MIN(max12,max34),MG_MAX(min12,min34));
338
339 /* compute key and insert */
340 key = (MMG5_KA*(int64_t)mins+MMG5_KB*(int64_t)mins_b+MMG5_KC*(int64_t)maxs)%hsize+1;
341 iadr++;
342 link[iadr] = hcode[key];
343 hcode[key] = -iadr;
344 }
345 }
346
347 /* set adjacency */
348 if ( mesh->info.ddebug ) fprintf(stdout," h- stage 2: adjacencies\n");
349 for (l=iadr; l>0; l--) {
350 if ( link[l] >= 0 ) continue;
351
352 /* current element */
353 k = (l-1) / 5 + 1;
354 i = (l-1) % 5;
355
356 switch (i)
357 {
358 case 0:
359 case 1:
360 i1 = MMG5_idir_pr[i][0];
361 i2 = MMG5_idir_pr[i][1];
362 i3 = MMG5_idir_pr[i][2];
363 pp = &mesh->prism[k];
364
365 min12 = MG_MIN(pp->v[i1],pp->v[i2]);
366 mins = MG_MIN(min12,pp->v[i3]);
367
368 max12 = MG_MAX(pp->v[i1],pp->v[i2]);
369 maxs = MG_MAX(max12,pp->v[i3]);
370
371 mins_b = pp->v[i1] + pp->v[i2] + pp->v[i3] - mins - maxs;
372
373 break;
374
375 default:
376 i1 = MMG5_idir_pr[i][0];
377 i2 = MMG5_idir_pr[i][1];
378 i3 = MMG5_idir_pr[i][2];
379 i4 = MMG5_idir_pr[i][3];
380 pp = &mesh->prism[k];
381
382 min12 = MG_MIN(pp->v[i1],pp->v[i2]);
383 min34 = MG_MIN(pp->v[i3],pp->v[i4]);
384 mins = MG_MIN(min12,min34);
385
386 max12 = MG_MAX(pp->v[i1],pp->v[i2]);
387 max34 = MG_MAX(pp->v[i3],pp->v[i4]);
388 maxs = MG_MAX(max12,max34);
389
390 mins_b = MG_MIN( MG_MIN(max12,max34),MG_MAX(min12,min34));
391 }
392
393 /* accross link */
394 ll = -link[l];
395 jj = 0;
396 link[l] = 0;
397 while ( ll != inival ) {
398 kk = (ll-1) / 5 + 1;
399 ii = (ll-1) % 5;
400
401 switch (ii)
402 {
403 case 0:
404 case 1:
405 i1 = MMG5_idir_pr[ii][0];
406 i2 = MMG5_idir_pr[ii][1];
407 i3 = MMG5_idir_pr[ii][2];
408
409 pp1 = &mesh->prism[kk];
410
411 min12 = MG_MIN(pp1->v[i1],pp1->v[i2]);
412 mins1 = MG_MIN(min12,pp1->v[i3]);
413
414 max12 = MG_MAX(pp1->v[i1],pp1->v[i2]);
415 maxs1 = MG_MAX(max12,pp1->v[i3]);
416
417 mins_b1 = pp1->v[i1] + pp1->v[i2] + pp1->v[i3] - mins1 - maxs1;
418
419 break;
420
421 default:
422 i1 = MMG5_idir_pr[ii][0];
423 i2 = MMG5_idir_pr[ii][1];
424 i3 = MMG5_idir_pr[ii][2];
425 i4 = MMG5_idir_pr[ii][3];
426 pp1 = &mesh->prism[kk];
427
428 min12 = MG_MIN(pp1->v[i1],pp1->v[i2]);
429 min34 = MG_MIN(pp1->v[i3],pp1->v[i4]);
430 mins1 = MG_MIN(min12,min34);
431
432 max12 = MG_MAX(pp1->v[i1],pp1->v[i2]);
433 max34 = MG_MAX(pp1->v[i3],pp1->v[i4]);
434 maxs1 = MG_MAX(max12,max34);
435
436 mins_b1 = MG_MIN( MG_MIN(max12,max34),MG_MAX(min12,min34));
437 }
438
439 /* adjacent found */
440 if ( mins1 == mins && maxs1 == maxs && mins_b1 == mins_b ) {
441 if ( jj != 0 ) link[jj] = link[ll];
442 link[l] = 5*kk + ii;
443 link[ll] = 5*k + i;
444 break;
445 }
446
447 jj = ll;
448 ll = -link[ll];
449 }
450 }
451 MMG5_SAFE_FREE(hcode);
452 return 1;
453}
454
469static inline
471 MMG5_pTetra pt;
472 MMG5_pxTetra pxt;
473 MMG5_pTria ptt;
474 MMG5_hedge *ph;
475 MMG5_int adj,pradj,piv;
476 int64_t list[MMG3D_LMAX+2];
477 MMG5_int key;
478 MMG5_int k,l,i1,i2,na,nb,ia,it1,it2, nr;
479 MMG5_int start;
480 int ilist,nbdy,ipa,ipb;
481 int8_t iface,hasadja,i;
482 static int8_t mmgWarn0=0,mmgWarn1=0;
483
484 nr = 0;
485
486 /* First: seek edges at the interface of two distinct domains and mark it as
487 * required */
488 for (k=1; k<=mesh->nt; k++) {
489 ptt = &mesh->tria[k];
490
491 if ( !MG_EOK(ptt) ) continue;
492
493 for (l=0; l<3; l++) {
494
495 /* Skip parallel edges */
496 if ( (ptt->tag[l] & MG_PARBDY) || (ptt->tag[l] & MG_BDY) ) continue;
497
498 if ( ptt->tag[l] & MG_NOM ) {
499 i1 = MMG5_inxt2[l];
500 i2 = MMG5_iprv2[l];
501
502 /* compute key */
503 na = MG_MIN(ptt->v[i1],ptt->v[i2]);
504 nb = MG_MAX(ptt->v[i1],ptt->v[i2]);
505 key = (MMG5_KA*na + MMG5_KB*nb) % hash->siz;
506 ph = &hash->item[key];
507
508 assert(ph->a);
509 while ( ph->a ) {
510 if ( ph->a == na && ph->b == nb ) break;
511 assert(ph->nxt);
512 ph = &hash->item[ph->nxt];
513 }
514 /* Set edge tag and point tags to MG_REQ if the non-manifold edge shared
515 * separated domains */
516 if ( ph->s > 3 ) {
517 start = ptt->cc/4;
518 assert(start);
519 pt = &mesh->tetra[start];
520
521
522 for (ia=0; ia<6; ++ia) {
523 ipa = MMG5_iare[ia][0];
524 ipb = MMG5_iare[ia][1];
525 if ( (pt->v[ipa] == na && pt->v[ipb] == nb) ||
526 (pt->v[ipa] == nb && pt->v[ipb] == na)) break;
527 }
528 assert(ia<6);
529
530
531 /* Travel throug the shell of the edge until reaching a tetra without adjacent
532 * or until reaching the starting tetra */
533 iface = ptt->cc%4;
534 MMG3D_coquilFaceFirstLoop(mesh,start,na,nb,iface,ia,list,&ilist,&it1,&it2,
535 &piv,&adj,&hasadja,&nbdy,1);
536
537 /* At this point, the first travel, in one direction, of the shell is
538 complete. Now, analyze why the travel ended. */
539 if ( adj == start ) {
540 if ( !it2 ) {
541 if ( !mmgWarn0 ) {
542 mmgWarn0 = 1;
543 fprintf(stderr,"\n ## Warning: %s: at least 1 wrong boundary tag:"
544 " Only 0 or 1 boundary triangles founded in the shell of the edge\n",
545 __func__);
546 }
547 }
548 if ( nbdy < 2 )
549 MMG5_coquilFaceErrorMessage(mesh, it1/4, it2/4);
550 }
551 else {
552 /* A boundary has been detected : slightly different configuration */
553 if ( hasadja ) {
554
555 /* Start back everything from this tetra adj */
556 MMG3D_coquilFaceSecondLoopInit(mesh,piv,&iface,&i,list,&ilist,&it1,
557 &pradj,&adj);
558
559 nbdy = 1;
560 while ( adj ) {
561 pradj = adj;
562
563 if ( MMG5_openCoquilTravel(mesh,na,nb,&adj,&piv,&iface,&i)<0 ) {
564 return 0;
565 }
566
567 /* overflow */
568 if ( ++ilist > MMG3D_LMAX-2 ) {
569 if ( !mmgWarn1 ) {
570 mmgWarn1 = 1;
571 fprintf(stderr,"\n ## Warning: %s: problem in surface remesh"
572 " process. At least 1 shell of edge (%" MMG5_PRId "-%" MMG5_PRId ") contains"
573 " too many elts.\n",__func__,MMG3D_indPt(mesh,na),
574 MMG3D_indPt(mesh,nb));
575 fprintf(stderr,"\n ## Try to modify the hausdorff"
576 " number, or/and the maximum mesh.\n");
577 }
578 return 0;
579 }
580
581 pt = &mesh->tetra[pradj];
582 if ( pt->xt ) {
583 pxt = &mesh->xtetra[pt->xt];
584 if ( pxt->ftag[iface] & MG_BDY ) ++nbdy;
585 }
586 }
587
588 assert(!adj);
589 it2 = 4*pradj + iface;
590
591 if ( (!it1 || !it2) || (it1 == it2) ) {
592 MMG5_coquilFaceErrorMessage(mesh, it1/4, it2/4);
593 return 0;
594 }
595 }
596 }
597
598 /* If ph->s do not match the number of encountred boundaries we have
599 separated domains. */
600 if ( nbdy != ph->s ) {
601 if ( !(ptt->tag[l] & MG_REQ) ) {
602 ptt->tag[l] |= MG_REQ;
603 ptt->tag[l] &= ~MG_NOSURF;
604 ++nr;
605 }
606 mesh->point[ptt->v[MMG5_inxt2[l]]].tag |= MG_REQ;
607 mesh->point[ptt->v[MMG5_iprv2[l]]].tag |= MG_REQ;
608 mesh->point[ptt->v[MMG5_inxt2[l]]].tag &= ~MG_NOSURF;
609 mesh->point[ptt->v[MMG5_iprv2[l]]].tag &= ~MG_NOSURF;
610 }
611
612 /* Work done for this edge: reset ph->s/ */
613 ph->s = 0;
614 }
615 }
616 }
617 }
618 if ( mesh->info.ddebug || abs(mesh->info.imprim) > 3 )
619 fprintf(stdout," %" MMG5_PRId " required edges added\n",nr);
620
621 /* Free the edge hash table */
622 MMG5_DEL_MEM(mesh,hash->item);
623 return 1;
624}
625
637static inline
639 MMG5_pTetra ptet;
640 MMG5_pPoint ppt;
641 MMG5_Hash hash;
642 int i,ier;
643 MMG5_int k,base,np,nc,nm,nre, ng, nrp;
644
645 /* Second: seek the non-required non-manifold points and try to analyse
646 * whether they are corner or required. */
647
648 /* Hash table used by boulernm to store the special edges passing through
649 * a given point */
650 np = 0;
651 for (k=1; k<=mesh->np; ++k) {
652 ppt = &mesh->point[k];
653 if ( (!(ppt->tag & MG_NOM)) || (ppt->tag & MG_REQ) ) continue;
654 ++np;
655 }
656
657 if ( ! MMG5_hashNew(mesh,&hash,np,(MMG5_int)(3.71*np)) ) return 0;
658
659 nc = nre = 0;
660 base = ++mesh->base;
661 for (k=1; k<=mesh->ne; ++k) {
662 ptet = &mesh->tetra[k];
663 if ( !MG_EOK(ptet) ) continue;
664
665 for ( i=0; i<4; ++i ) {
666 ppt = &mesh->point[ptet->v[i]];
667
668 /* Skip parallel points */
669 if ( ppt->tag & MG_PARBDY ) continue;
670
671 if ( (!MG_VOK(ppt)) || (ppt->flag==base) ) continue;
672 ppt->flag = base;
673
674 if ( (!(ppt->tag & MG_NOM)) || (ppt->tag & MG_REQ) ) continue;
675
676 ier = MMG5_boulernm(mesh,&hash, k, i, &ng, &nrp, &nm);
677 if ( ier < 0 ) return 0;
678 else if ( !ier ) continue;
679
680 if ( (ng+nrp+nm) > 2 ) {
681 /* More than 2 feature edges are passing through the point: point is
682 * marked as corner */
683 ppt->tag |= MG_CRN + MG_REQ;
684 ppt->tag &= ~MG_NOSURF;
685 nre++;
686 nc++;
687 }
688 else if ( (ng == 2) || (nrp == 2) || (nm == 2) ) {
689 /* Exactly 2 edges of same type are passing through the point: do
690 * nothing */
691 continue;
692 }
693 else if ( (ng+nrp+nm) == 2 ) {
694 /* 2 edges of different type are passing through the point: point is
695 * marked as required */
696 ppt->tag |= MG_REQ;
697 ppt->tag &= ~MG_NOSURF;
698 nre++;
699 }
700 else if ( ng == 1 && !nrp ){
701 ppt->tag |= MG_CRN + MG_REQ;
702 ppt->tag &= ~MG_NOSURF;
703 nre++;
704 nc++;
705 }
706 else if ( (ng+nrp+nm) == 1 ){
707 /* Only 1 feature edge is passing through the point: point is
708 * marked as corner */
709 assert ( (ng == 1) || (nrp==1) || (nm==1) );
710 ppt->tag |= MG_CRN + MG_REQ;
711 ppt->tag &= ~MG_NOSURF;
712 nre++;
713 nc++;
714 }
715 else {
716 assert ( 0 && "unexpected case");
717 }
718 }
719 }
720
721 /* Free the edge hash table */
722 MMG5_DEL_MEM(mesh,hash.item);
723
724 if ( mesh->info.ddebug || abs(mesh->info.imprim) > 3 )
725 fprintf(stdout," %" MMG5_PRId " corner and %" MMG5_PRId " required vertices added\n",nc,nre);
726
727 return 1;
728}
729
742
743 /* First: seek edges at the interface of two distinct domains and mark it as
744 * required */
745 if ( !MMG5_setEdgeNmTag(mesh,hash) ) return 0;
746
747 /* Second: seek the non-required non-manifold points and try to analyse
748 * whether they are corner or required. */
749 if ( !MMG5_setVertexNmTag(mesh) ) return 0;
750
751 return 1;
752}
753
764
766
767 MMG5_ADD_MEM(mesh,(3*mesh->nt+4)*sizeof(MMG5_int),"surfacic adjacency table",return 0);
768 MMG5_SAFE_CALLOC(mesh->adjt,3*mesh->nt+4,MMG5_int,return 0);
769
770 return MMG5_mmgHashTria(mesh, mesh->adjt, hash, mesh->info.iso) ;
771}
772
773
775int MMG5_hashPop(MMG5_Hash *hash,MMG5_int a,MMG5_int b) {
776 MMG5_hedge *ph,*php;
777 MMG5_int key;
778 MMG5_int ia,ib,iph,iphp;
779
780 ia = MG_MIN(a,b);
781 ib = MG_MAX(a,b);
782 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
783 ph = &hash->item[key];
784
785 if ( !ph->a ) return 0;
786 else if ( ph->a == ia && ph->b == ib ) {
787 if ( !ph->nxt ) {
788 memset(ph,0,sizeof(MMG5_hedge));
789 return 1;
790 }
791 else {
792 iph = ph->nxt;
793 php = ph;
794 ph = &hash->item[ph->nxt];
795 memcpy(php,ph,sizeof(MMG5_hedge));
796 memset(ph,0,sizeof(MMG5_hedge));
797 ph->nxt = hash->nxt;
798 hash->nxt = iph;
799 return 1;
800 }
801 }
802 while ( ph->nxt ) {
803 php = ph;
804 ph = &hash->item[ph->nxt];
805 if ( ph->a == ia && ph->b == ib ) {
806 if ( !ph->nxt ) {
807 memset(ph,0,sizeof(MMG5_hedge));
808 ph->nxt = hash->nxt;
809 hash->nxt = php->nxt;
810 php->nxt = 0;
811 }
812 else {
813 iph = ph->nxt;
814 iphp = php->nxt;
815 php->nxt = iph;
816 memset(ph,0,sizeof(MMG5_hedge));
817 ph->nxt = hash->nxt;
818 hash->nxt = iphp;
819 }
820 return 1;
821 }
822 }
823 return 0;
824}
825
826
839int MMG5_hTag(MMG5_HGeom *hash,MMG5_int a,MMG5_int b,MMG5_int ref,int16_t tag) {
840 MMG5_hgeom *ph;
841 MMG5_int key;
842 MMG5_int ia,ib;
843
844 ia = MG_MIN(a,b);
845 ib = MG_MAX(a,b);
846 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
847 ph = &hash->geom[key];
848
849 if ( !ph->a )
850 return 0;
851 else if ( ph->a == ia && ph->b == ib ) {
852 ph->tag |= tag;
853 if ( ref ) {
854 ph->ref = ref;
855 }
856 return 1;
857 }
858 while ( ph->nxt ) {
859 ph = &hash->geom[ph->nxt];
860 if ( ph->a == ia && ph->b == ib ) {
861 ph->tag |= tag;
862 if ( ref ) {
863 ph->ref = ref;
864 }
865 return 1;
866 }
867 }
868 return 0;
869}
870
872int MMG5_hPop(MMG5_HGeom *hash,MMG5_int a,MMG5_int b,MMG5_int *ref,int16_t *tag) {
873 MMG5_hgeom *ph,*php;
874 MMG5_int key;
875 MMG5_int ia,ib,iph,iphp;
876
877 *ref = 0;
878 *tag = 0;
879
880 assert ( hash->siz );
881
882 ia = MG_MIN(a,b);
883 ib = MG_MAX(a,b);
884 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
885 ph = &hash->geom[key];
886
887 if ( !ph->a ) return 0;
888 else if ( ph->a == ia && ph->b == ib ) {
889 *ref = ph->ref;
890 *tag = ph->tag;
891 if ( !ph->nxt ) {
892 memset(ph,0,sizeof(MMG5_hgeom));
893 }
894 else {
895 iph = ph->nxt;
896 php = ph;
897 ph = &hash->geom[ph->nxt];
898 memcpy(php,ph,sizeof(MMG5_hgeom));
899 memset(ph,0,sizeof(MMG5_hgeom));
900 ph->nxt = hash->nxt;
901 hash->nxt = iph;
902 }
903 return 1;
904 }
905 while ( ph->nxt ) {
906 php = ph;
907 ph = &hash->geom[ph->nxt];
908 if ( ph->a == ia && ph->b == ib ) {
909 *ref = ph->ref;
910 *tag = ph->tag;
911 if ( !ph->nxt ) {
912 memset(ph,0,sizeof(MMG5_hgeom));
913 ph->nxt = hash->nxt;
914 hash->nxt = php->nxt;
915 php->nxt = 0;
916 }
917 else {
918 iph = ph->nxt;
919 iphp = php->nxt;
920 php->nxt = iph;
921 memset(ph,0,sizeof(MMG5_hgeom));
922 ph->nxt = hash->nxt;
923 hash->nxt = iphp;
924 }
925 return 1;
926 }
927 }
928 return 0;
929}
930
932int MMG5_hGet(MMG5_HGeom *hash,MMG5_int a,MMG5_int b,MMG5_int *ref,int16_t *tag) {
933 MMG5_hgeom *ph;
934 MMG5_int key;
935 MMG5_int ia,ib;
936
937 *tag = 0;
938 *ref = 0;
939
940 assert ( hash->siz );
941
942 ia = MG_MIN(a,b);
943 ib = MG_MAX(a,b);
944 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
945 ph = &hash->geom[key];
946
947 if ( !ph->a ) return 0;
948 else if ( ph->a == ia && ph->b == ib ) {
949 *ref = ph->ref;
950 *tag = ph->tag;
951 return 1;
952 }
953 while ( ph->nxt ) {
954 ph = &hash->geom[ph->nxt];
955 if ( ph->a == ia && ph->b == ib ) {
956 *ref = ph->ref;
957 *tag = ph->tag;
958 return 1;
959 }
960 }
961 return 0;
962}
963
965int MMG5_hEdge(MMG5_pMesh mesh,MMG5_HGeom *hash,MMG5_int a,MMG5_int b,MMG5_int ref,int16_t tag) {
966 MMG5_hgeom *ph;
967 MMG5_int key;
968 MMG5_int ia,ib,j;
969
970 assert ( hash->siz );
971
972 ia = MG_MIN(a,b);
973 ib = MG_MAX(a,b);
974 key = (MMG5_KA*(int64_t)ia + MMG5_KB*(int64_t)ib) % hash->siz;
975 ph = &hash->geom[key];
976
977 if ( ph->a == ia && ph->b == ib )
978 return 1;
979 else if ( ph->a ) {
980 while ( ph->nxt ) {
981 ph = &hash->geom[ph->nxt];
982 if ( ph->a == ia && ph->b == ib ) return 1;
983 }
984 ph->nxt = hash->nxt;
985 ph = &hash->geom[hash->nxt];
986 ph->a = ia; ph->b = ib;
987 ph->ref = ref; ph->tag = tag;
988 hash->nxt = ph->nxt;
989 ph->nxt = 0;
990 if ( hash->nxt >= hash->max ) {
991 if ( mesh->info.ddebug )
992 fprintf(stderr,"\n ## Memory alloc problem (edge): %" MMG5_PRId "\n",hash->max);
994 "larger htab table",
995 fprintf(stderr," Exit program.\n");return 0;);
996 for (j=hash->nxt; j<hash->max; j++) hash->geom[j].nxt = j+1;
997 }
998 return 1;
999 }
1000 /* insert new edge */
1001 ph->a = ia; ph->b = ib;
1002 ph->ref = ref; ph->tag = tag;
1003 ph->nxt = 0;
1004 return 1;
1005}
1006
1008int MMG5_hNew(MMG5_pMesh mesh,MMG5_HGeom *hash,MMG5_int hsiz,MMG5_int hmax) {
1009 MMG5_int k;
1010
1011 /* adjust hash table params */
1012 hash->siz = hsiz + 1;
1013 hash->max = hmax + 2;
1014 hash->nxt = hash->siz;
1015
1016 MMG5_ADD_MEM(mesh,(hash->max+1)*sizeof(MMG5_hgeom),"Edge hash table",return 0);
1017 MMG5_SAFE_CALLOC(hash->geom,(hash->max+1),MMG5_hgeom,return 0);
1018
1019 if ( !hash->geom ) {
1020 perror(" ## Memory problem: calloc");
1021 return 0;
1022 }
1023 for (k=hash->siz; k<hash->max; k++)
1024 hash->geom[k].nxt = k+1;
1025
1026 return 1;
1027}
1028
1037 MMG5_pTria pt;
1038 MMG5_pEdge pa;
1039 MMG5_Hash hash;
1040 MMG5_int edg,*adja,k,kk;
1041 int ier;
1042 int16_t tag;
1043 int8_t i,i1,i2;
1044
1045 /* if edges exist in mesh, hash special edges from existing field */
1046 if ( mesh->na ) {
1047 if ( !mesh->htab.geom ) {
1048 mesh->namax = MG_MAX((MMG5_int)(1.5*mesh->na),MMG3D_NAMAX);
1049 if ( !MMG5_hNew(mesh,&mesh->htab,mesh->na,3*mesh->namax) )
1050 return 0;
1051 }
1052 else {
1053 if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) {
1054 fprintf(stderr,"\n ## Warning: %s: no re-hash of edges of mesh. ",
1055 __func__);
1056 fprintf(stderr,"mesh->htab.geom must be freed to enforce analysis.\n");
1057 }
1059 mesh->na = 0;
1060 return 1;
1061 }
1062
1063 /* store initial edges */
1064 for (k=1; k<=mesh->na; k++) {
1065 pa = &mesh->edge[k];
1066 if ( !MMG5_hEdge(mesh,&mesh->htab,pa->a,pa->b,pa->ref,pa->tag) )
1067 return 0;
1068 }
1069
1070 /* now check triangles */
1071 for (k=1; k<=mesh->nt; k++) {
1072 pt = &mesh->tria[k];
1073 for (i=0; i<3; i++) {
1074 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
1075 i1 = MMG5_inxt2[i];
1076 i2 = MMG5_iprv2[i];
1077 /* transfer non manifold tag to edges */
1078 if ( pt->tag[i] & MG_NOM ) {
1079 ier = MMG5_hTag(&mesh->htab,pt->v[i1],pt->v[i2],pt->edg[i],pt->tag[i]);
1080 if ( !ier ) {
1081 /* The edge is marked as non manifold but doesn't exist in the mesh */
1082 ier = MMG5_hEdge(mesh,&mesh->htab,pt->v[i1],pt->v[i2],pt->edg[i],pt->tag[i]);
1083 if ( !ier )
1084 return 0;
1085 }
1086 }
1087 MMG5_hGet(&mesh->htab,pt->v[i1],pt->v[i2],&edg,&tag);
1088 pt->edg[i] = edg;
1089
1090 /* If we use the nosurf option and the edge is required, we don't want
1091 * to detect it as an edge whose tag has been modified for the option */
1092 if ( mesh->info.nosurf && (tag & MG_REQ) )
1093 pt->tag[i] &= ~MG_NOSURF;
1094
1095 /* Store the edge tag inside the triangle */
1096 pt->tag[i] |= tag;
1097
1098 MMG5_hTag(&mesh->htab,pt->v[i1],pt->v[i2],edg,pt->tag[i]);
1099 }
1100 }
1102 mesh->na = 0;
1103 }
1104 /* else, infer special edges from information carried by triangles */
1105 else {
1106 if ( !mesh->adjt ) {
1107 memset(&hash,0x0,sizeof(MMG5_Hash));
1108 ier = MMG3D_hashTria(mesh,&hash);
1109 MMG5_DEL_MEM(mesh,hash.item);
1110 if ( !ier ) return 0;
1111 }
1112
1113 for (k=1; k<=mesh->nt; k++) {
1114 pt = &mesh->tria[k];
1115 adja = &mesh->adjt[3*(k-1)+1];
1116 for (i=0; i<3; i++) {
1117 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
1118 kk = adja[i] / 3;
1119 if ( !kk || pt->tag[i] & MG_NOM )
1120 mesh->na++;
1121 else if ( (k < kk) && ( pt->edg[i] || pt->tag[i] ) ) mesh->na++;
1122 }
1123 }
1124
1125 if ( mesh->htab.geom )
1127
1128 mesh->namax = MG_MAX((MMG5_int)(1.5*mesh->na),MMG3D_NAMAX);
1129 if ( !MMG5_hNew(mesh,&mesh->htab,mesh->na,3*mesh->namax) )
1130 return 0;
1131
1132 mesh->na = 0;
1133
1134 /* build hash for edges */
1135 for (k=1; k<=mesh->nt; k++) {
1136 pt = &mesh->tria[k];
1137 adja = &mesh->adjt[3*(k-1)+1];
1138 for (i=0; i<3; i++) {
1139 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
1140 i1 = MMG5_inxt2[i];
1141 i2 = MMG5_iprv2[i];
1142 kk = adja[i] / 3;
1143 if ( (!kk) || pt->tag[i] & MG_NOM ) {
1144 if ( pt->tag[i] & MG_NOM ) {
1145 if ( mesh->info.iso )
1146 pt->edg[i] = ( pt->edg[i] != 0 ) ? -MMG5_abs(pt->edg[i]) : mesh->info.isoref;
1147 }
1148 if ( !MMG5_hEdge(mesh,&mesh->htab,pt->v[i1],pt->v[i2],pt->edg[i],pt->tag[i]) )
1149 return 0;
1150 }
1151 else if ( k < kk && ( pt->edg[i] || pt->tag[i] ) ) {
1152 if ( !MMG5_hEdge(mesh,&mesh->htab,pt->v[i1],pt->v[i2],pt->edg[i],pt->tag[i]))
1153 return 0;
1154 }
1155 }
1156 }
1157 /* now check triangles */
1158 for (k=1; k<=mesh->nt; k++) {
1159 pt = &mesh->tria[k];
1160 for (i=0; i<3; i++) {
1161 if( (pt->tag[i] & MG_PARBDY) && !(pt->tag[i] & MG_PARBDYBDY) ) continue;
1162 i1 = MMG5_inxt2[i];
1163 i2 = MMG5_iprv2[i];
1164 MMG5_hGet(&mesh->htab,pt->v[i1],pt->v[i2],&edg,&tag);
1165 pt->edg[i] = edg;
1166 pt->tag[i] |= tag;
1167 }
1168 }
1169 }
1170 return 1;
1171}
1172
1190static inline
1191int MMG5_bdryTria(MMG5_pMesh mesh, MMG5_int ntmesh) {
1192 MMG5_pTetra pt,pt1;
1193 MMG5_pPrism pp;
1194 MMG5_pTria ptt;
1195 MMG5_pPoint ppt;
1196 MMG5_pxTetra pxt;
1197 MMG5_pxPrism pxpr;
1198 MMG5_Hash hash;
1199 MMG5_int ref,*adja,adj,k,ia,ib,ic,kt,ntinit;
1200 int tofree=0;
1201 int8_t i,j;
1202
1203 hash.item = NULL;
1204
1205 ntinit = mesh->nt;
1206
1207 if ( mesh->nprism && (ntmesh!=ntinit) ) {
1208 /* If a triangle at the interface between a prism and a tetra is not
1209 * provided, the hashtable is used to recover from the prism a boundary tria
1210 * created by tetra */
1211 if ( ! MMG5_hashNew(mesh,&hash,0.51*ntmesh,1.51*ntmesh) ) return 0;
1212 tofree=1;
1213 }
1214 else if ( mesh->nt ) {
1215 /* Hash given bdry triangles */
1216 if ( ! MMG5_hashNew(mesh,&hash,(MMG5_int)(0.51*mesh->nt),(MMG5_int)(1.51*mesh->nt)) ) return 0;
1217 tofree=1;
1218 }
1219
1220 for (k=1; k<=mesh->nt; k++) {
1221 ptt = &mesh->tria[k];
1222 if ( !MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k) ) {
1223 MMG5_DEL_MEM(mesh,hash.item);
1224 return 0;
1225 }
1226 for (i=0; i<3; i++) {
1227 ppt = &mesh->point[ptt->v[i]];
1228 if ( !mesh->info.iso ) ppt->tag |= MG_BDY;
1229 }
1230 }
1231
1232 /* Add boundary triangles stored on tetra */
1233 if ( ntmesh != ntinit ) {
1234 for (k=1; k<=mesh->ne; k++) {
1235 pt = &mesh->tetra[k];
1236 if ( !MG_EOK(pt) ) continue;
1237 adja = &mesh->adja[4*(k-1)+1];
1238 pxt = 0;
1239 if ( pt->xt ) pxt = &mesh->xtetra[pt->xt];
1240 for (i=0; i<4; i++) {
1241 adj = adja[i] / 4;
1242 pt1 = &mesh->tetra[adj];
1243
1244 if ( (!mesh->info.opnbdy) || (!mesh->xtetra) ) {
1245 /* Classic mode (no open bdy) or no info stored in xtetra (first
1246 * call) */
1247 if ( adj && ( pt->ref <= pt1->ref) ) continue;
1248 } else {
1249 /* info stored in xtetra and opnbdy mode */
1250 if ( adj && ( (pt->ref<pt1->ref) || (!pt->xt) ||
1251 (!(pxt->ftag[i] & MG_BDY)) || (!MG_GET(pxt->ori,i) ) ) )
1252 continue;
1253 }
1254
1255 ia = pt->v[MMG5_idir[i][0]];
1256 ib = pt->v[MMG5_idir[i][1]];
1257 ic = pt->v[MMG5_idir[i][2]];
1258
1259 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1260 if ( kt ) {
1261 /* Face is already stored */
1262 continue;
1263 }
1264 else if ( mesh->nprism ) {
1265 /* Update the list of boundary trias to be able to recover tria at the
1266 * interface between tet and prisms */
1267 if ( !MMG5_hashFace(mesh,&hash,ia,ib,ic,mesh->nt+1) ) {
1268 MMG5_DEL_MEM(mesh,hash.item);
1269 return 0;
1270 }
1271 }
1272
1273 /* face does not exists: add it in tria array */
1274 mesh->nt++;
1275 ptt = &mesh->tria[mesh->nt];
1276 ptt->v[0] = pt->v[MMG5_idir[i][0]];
1277 mesh->point[ptt->v[0]].tag |= MG_BDY;
1278 ptt->v[1] = pt->v[MMG5_idir[i][1]];
1279 mesh->point[ptt->v[1]].tag |= MG_BDY;
1280 ptt->v[2] = pt->v[MMG5_idir[i][2]];
1281 mesh->point[ptt->v[2]].tag |= MG_BDY;
1282
1283 /* the cc field is used to be able to recover the tetra (and its face)
1284 * from which comes a boundary triangle (when called by packmesh =>
1285 * mesh->nt=0 at the beginning of the function) */
1286 ptt->cc = 4*k + i;
1287
1288 if ( pxt ) {
1289 /* useful only when saving mesh or in ls mode */
1290 for( j = 0; j < 3; j++ ) {
1291 if ( pxt->tag[MMG5_iarf[i][j]] ) {
1292 ptt->tag[j] = pxt->tag[MMG5_iarf[i][j]];
1293 /* Remove redundant boundary tag */
1294 ptt->tag[j] &= ~MG_BDY;
1295 }
1296 if ( pxt->edg[MMG5_iarf[i][j]] )
1297 ptt->edg[j] = pxt->edg[MMG5_iarf[i][j]];
1298 }
1299 }
1300 if ( adj ) {
1301 if ( mesh->info.iso ) {
1302 /* Triangle at the interface between two tets is set to the user-defined ref if any, or else to mesh->info.isoref ref */
1303 if ( pxt && pxt->ftag[i] & MG_BDY )
1304 ptt->ref = pxt->ref[i];
1305 else if( MMG5_isLevelSet(mesh,pt->ref,pt1->ref) )
1306 ptt->ref = mesh->info.isoref;
1307 else
1308 ptt->ref = MG_MIN(pt->ref,pt1->ref);
1309 }
1310 /* useful only when saving mesh or in ls mode */
1311 else {
1312 /* Triangle at the interface between two tet is set its init ref or
1313 * to the min ref of the adja tetra */
1314 ptt->ref = pxt ? pxt->ref[i] : MG_MIN(pt->ref,pt1->ref);
1315 }
1316 }
1317 else {
1318 /* useful only when saving mesh */
1319 ptt->ref = pxt ? pxt->ref[i] : pt->ref;
1320 }
1321 }
1322 }
1323 }
1324
1325 /* Add boundary triangles stored on prisms */
1326 if ( mesh->nprism ) {
1327 for (k=1; k<=mesh->nprism; k++) {
1328 pp = &mesh->prism[k];
1329 if ( !MG_EOK(pp) ) continue;
1330
1331 adja = &mesh->adjapr[5*(k-1)+1];
1332 pxpr = 0;
1333 if ( pp->xpr ) pxpr = &mesh->xprism[pp->xpr];
1334
1335 for (i=0; i<2; i++) {
1336 adj = adja[i]/5;
1337
1338
1339 if ( adj < 0 ) {
1340 if ( !mesh->nt ) continue;
1341
1342 /* Tria at the interface of a prism and a tetra: mark it as required */
1343 ia = pp->v[0+i*3];
1344 ib = pp->v[1+i*3];
1345 ic = pp->v[2+i*3];
1346
1347 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1348 if ( !kt ) continue;
1349
1350 ptt = &mesh->tria[kt];
1351
1352 if ( !(ptt->tag[0] & MG_REQ) ) {
1353 ptt->tag[0] |= MG_REQ;
1354 ptt->tag[0] |= MG_NOSURF;
1355 }
1356 if ( !(ptt->tag[1] & MG_REQ) ) {
1357 ptt->tag[1] |= MG_REQ;
1358 ptt->tag[1] |= MG_NOSURF;
1359 }
1360 if ( !(ptt->tag[2] & MG_REQ) ) {
1361 ptt->tag[2] |= MG_REQ;
1362 ptt->tag[2] |= MG_NOSURF;
1363 }
1364
1365 continue;
1366 }
1367
1368 ref = mesh->prism[adj].ref;
1369 if ( adj && ( pp->ref <= ref) ) continue;
1370
1371 ia = pp->v[0+i*3];
1372 ib = pp->v[1+i*3];
1373 ic = pp->v[2+i*3];
1374
1375 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1376 if ( kt ) {
1377 continue;
1378 }
1379
1380 mesh->nt++;
1381
1382 ptt = &mesh->tria[mesh->nt];
1383 ptt->v[0] = ia;
1384 ptt->v[1] = ib;
1385 ptt->v[2] = ic;
1386 mesh->point[ptt->v[0]].tag |= MG_BDY;
1387 mesh->point[ptt->v[1]].tag |= MG_BDY;
1388 mesh->point[ptt->v[2]].tag |= MG_BDY;
1389
1390 /* the cc field is used to be able to recover the prism (and its face)
1391 * from which comes a boundary triangle (when called by packmesh =>
1392 * mesh->nt=0 at the beginning of the function) */
1393 ptt->cc = 5*k + i;
1394 if ( pxpr ) {
1395 /* useful only when saving mesh */
1396 if ( pxpr->tag[MMG5_iarf_pr[i][0]] ) ptt->tag[0] = pxpr->tag[MMG5_iarf_pr[i][0]];
1397 if ( pxpr->tag[MMG5_iarf_pr[i][1]] ) ptt->tag[1] = pxpr->tag[MMG5_iarf_pr[i][1]];
1398 if ( pxpr->tag[MMG5_iarf_pr[i][2]] ) ptt->tag[2] = pxpr->tag[MMG5_iarf_pr[i][2]];
1399 }
1400 if ( adj ) {
1401 if ( mesh->info.iso ) ptt->ref = mesh->info.isoref;
1402 /* useful only when saving mesh */
1403 else ptt->ref = pxpr ? pxpr->ref[i] : 0;
1404 }
1405 else {
1406 /* useful only when saving mesh */
1407 ptt->ref = pxpr ? pxpr->ref[i] : 0;
1408 }
1409 }
1410 }
1411 }
1412
1413 assert(mesh->nt==ntmesh);
1414
1415 if ( ntmesh != ntinit ) {
1416 /* set point tag */
1417 for (k=1; k<=mesh->nt; k++) {
1418 ptt = &mesh->tria[k];
1419 for (i=0; i<3; i++) {
1420 ppt = &mesh->point[ptt->v[i]];
1421 ppt->tag |= MG_BDY;
1422 }
1423 }
1424 }
1425
1426 if ( tofree ) MMG5_DEL_MEM(mesh,hash.item);
1427
1428 return 1;
1429}
1430
1454 MMG5_pTetra pt,pt1;
1455 MMG5_pPrism pp,pp1;
1456 MMG5_pTria ptt,pttnew;
1457 MMG5_int *adja,adj,k,kk,i,j,ntmesh;
1458 MMG5_int ia,ib,ic, nbl,nt,ntpres;
1459 int iface;
1460 MMG5_Hash hashElt, hashTri;
1461
1463 ntmesh = ntpres = 0;
1464 for (k=1; k<=mesh->ne; k++) {
1465 pt = &mesh->tetra[k];
1466 if ( !MG_EOK(pt) ) continue;
1467 adja = &mesh->adja[4*(k-1)+1];
1468 for (i=0; i<4; i++) {
1469 adj = adja[i];
1470
1471 if ( !adj ) {
1472 ++ntmesh;
1473 continue;
1474 }
1475 adj /= 4;
1476 pt1 = &mesh->tetra[adj];
1477 if ( pt->ref > pt1->ref )
1478 ++ntmesh;
1479 }
1480 }
1481
1482 if ( mesh->info.opnbdy && mesh->xtetra ) {
1483 /* We want to preserve internal triangle and we came from bdryBuild: we need
1484 * to count the preserved boudaries */
1485 for (k=1; k<=mesh->ne; k++) {
1486 pt = &mesh->tetra[k];
1487 if ( !MG_EOK(pt) || !pt->xt ) continue;
1488 adja = &mesh->adja[4*(k-1)+1];
1489 for (i=0; i<4; i++) {
1490 adj = adja[i];
1491
1492 if ( !adj ) continue;
1493
1494 adj /= 4;
1495 pt1 = &mesh->tetra[adj];
1496
1497 if ( pt->ref != pt1->ref ) continue;
1498
1499 if ( (mesh->xtetra[pt->xt].ftag[i] & MG_BDY) &&
1500 (MG_GET(mesh->xtetra[pt->xt].ori,i) ) ) ++ntpres;
1501 }
1502 }
1503 }
1504
1505 if ( mesh->nprism ) {
1506 for (k=1; k<=mesh->nprism; k++) {
1507 pp = &mesh->prism[k];
1508 if ( !MG_EOK(pp) ) continue;
1509
1510 adja = &mesh->adjapr[5*(k-1)+1];
1511 for (i=0; i<2; i++) {
1512 adj = adja[i];
1513
1514 if ( !adj ) {
1515 ++ntmesh;
1516 continue;
1517 }
1518 else if ( adj<0 ) {
1519 continue;
1520 }
1521
1522 adj /= 5;
1523 pp1 = &mesh->prism[adj];
1524 if ( pp->ref > pp1->ref) {
1525 ++ntmesh;
1526 }
1527 }
1528 }
1529
1530 /* Detect the triangles at the interface of the prisms and tetra (they have been
1531 * counted twice) */
1532 if ( ! MMG5_hashNew(mesh,&hashTri,0.51*ntmesh,1.51*ntmesh) ) return 0;
1533 for (k=1; k<=mesh->ne; k++) {
1534 pt = &mesh->tetra[k];
1535 if ( !MG_EOK(pt) ) continue;
1536
1537 adja = &mesh->adja[4*(k-1)+1];
1538 for (i=0; i<4; i++) {
1539 adj = adja[i];
1540 if ( adj ) continue;
1541
1542 ia = pt->v[MMG5_idir[i][0]];
1543 ib = pt->v[MMG5_idir[i][1]];
1544 ic = pt->v[MMG5_idir[i][2]];
1545 if ( !MMG5_hashFace(mesh,&hashTri,ia,ib,ic,5*k+i) ) {
1546 MMG5_DEL_MEM(mesh,hashTri.item);
1547 return 0;
1548 }
1549 }
1550 }
1551
1552 /* Fill the adjacency relationship between prisms and tetra (fill adjapr with
1553 * a negative value to mark this special faces) */
1554 for (k=1; k<=mesh->nprism; k++) {
1555 pp = &mesh->prism[k];
1556 if ( !MG_EOK(pp) ) continue;
1557
1558 adja = &mesh->adjapr[5*(k-1)+1];
1559 for (i=0; i<2; i++) {
1560 adj = adja[i];
1561 if ( adj ) continue;
1562
1563 ia = pp->v[MMG5_idir_pr[i][0]];
1564 ib = pp->v[MMG5_idir_pr[i][1]];
1565 ic = pp->v[MMG5_idir_pr[i][2]];
1566
1567 j = MMG5_hashGetFace(&hashTri,ia,ib,ic);
1568 if ( !j ) continue;
1569
1570 --ntmesh;
1571 adja[i] = -j;
1572 }
1573 }
1574 MMG5_DEL_MEM(mesh,hashTri.item);
1575 }
1576
1579 if ( mesh->nt ) {
1580 if ( ! MMG5_hashNew(mesh,&hashElt,0.51*ntmesh,1.51*ntmesh) ) return 0;
1581 // Hash the boundaries found in the mesh
1582 if ( mesh->info.opnbdy) {
1583 /* We want to keep the internal triangles: we must hash all the tetra faces */
1584 for (k=1; k<=mesh->ne; k++) {
1585 pt = &mesh->tetra[k];
1586 if ( !MG_EOK(pt) ) continue;
1587
1588 for (i=0; i<4; i++) {
1589 ia = pt->v[MMG5_idir[i][0]];
1590 ib = pt->v[MMG5_idir[i][1]];
1591 ic = pt->v[MMG5_idir[i][2]];
1592 if ( !MMG5_hashFace(mesh,&hashElt,ia,ib,ic,4*k+i) ) return 0;
1593 }
1594 }
1595 } else {
1596 for (k=1; k<=mesh->ne; k++) {
1597 pt = &mesh->tetra[k];
1598 if ( !MG_EOK(pt) ) continue;
1599 adja = &mesh->adja[4*(k-1)+1];
1600 for (i=0; i<4; i++) {
1601 adj = adja[i];
1602 if ( !adj ) {
1603 ia = pt->v[MMG5_idir[i][0]];
1604 ib = pt->v[MMG5_idir[i][1]];
1605 ic = pt->v[MMG5_idir[i][2]];
1606 if ( !MMG5_hashFace(mesh,&hashElt,ia,ib,ic,4*k+i) ) return 0;
1607 }
1608 adj /= 4;
1609
1610 pt1 = &mesh->tetra[adj];
1611 if ( pt->ref > pt1->ref ) {
1612 ia = pt->v[MMG5_idir[i][0]];
1613 ib = pt->v[MMG5_idir[i][1]];
1614 ic = pt->v[MMG5_idir[i][2]];
1615 if ( !MMG5_hashFace(mesh,&hashElt,ia,ib,ic,4*k+i) ) return 0;
1616 }
1617 }
1618 }
1619 }
1620 for (k=1; k<=mesh->nprism; k++) {
1621 pp = &mesh->prism[k];
1622 if ( !MG_EOK(pp) ) continue;
1623 adja = &mesh->adjapr[5*(k-1)+1];
1624 for (i=0; i<2; i++) {
1625 adj = adja[i];
1626 if ( !adj ) {
1627 ia = pp->v[MMG5_idir_pr[i][0]];
1628 ib = pp->v[MMG5_idir_pr[i][1]];
1629 ic = pp->v[MMG5_idir_pr[i][2]];
1630 if ( !MMG5_hashFace(mesh,&hashElt,ia,ib,ic,5*k+i) ) return 0;
1631 }
1632 else if ( adj<0 ) continue;
1633
1634 adj /= 5;
1635
1636 pp1 = &mesh->prism[MMG5_abs(adj)];
1637 if ( pp->ref > pp1->ref ) {
1638 ia = pp->v[MMG5_idir_pr[i][0]];
1639 ib = pp->v[MMG5_idir_pr[i][1]];
1640 ic = pp->v[MMG5_idir_pr[i][2]];
1641 if ( !MMG5_hashFace(mesh,&hashElt,ia,ib,ic,5*k+i) ) return 0;
1642 }
1643 }
1644 }
1645
1646
1647 // Travel through the tria, delete those that are not in the hash tab or
1648 // that are stored more that once.
1649 nt=0; nbl=1;
1650
1651 if ( ! MMG5_hashNew(mesh,&hashTri,0.51*mesh->nt,1.51*mesh->nt) ) return 0;
1652
1653 for (k=1; k<=mesh->nt; k++) {
1654 ptt = &mesh->tria[k];
1655
1656 ia = ptt->v[0];
1657 ib = ptt->v[1];
1658 ic = ptt->v[2];
1659
1660 i = MMG5_hashGetFace(&hashElt,ia,ib,ic);
1661 j = MMG5_hashFace(mesh,&hashTri,ia,ib,ic,k);
1662
1663 ptt->cc = i;
1664
1665 if ( !j ) {
1666 MMG5_DEL_MEM(mesh,hashElt.item);
1667 MMG5_DEL_MEM(mesh,hashTri.item);
1668 return 0;
1669 }
1670 else if ( j > 0 ) {
1671 /* the face already exists in the tria table */
1672 continue;
1673 }
1674
1675 if ( !i ) {
1676 /* the triangle is not a boundary tri or a tri at the interface of two
1677 * subdomains with different references and the user don't ask to keep
1678 * it. */
1679 continue;
1680 }
1681
1682 if ( mesh->info.opnbdy ) {
1683 kk = i/4;
1684 iface = i%4;
1685 adj = mesh->adja[4*(kk-1)+1+iface];
1686 /* Check if we have found a triangle at the interface of 2 doms of same
1687 * ref */
1688 if ( adj && mesh->tetra[kk].ref == mesh->tetra[adj/4].ref ) {
1689 ++ntpres;
1690 }
1691 }
1692
1693 ++nt;
1694 if ( k!=nbl ) {
1695 pttnew = &mesh->tria[nbl];
1696 memcpy(pttnew,ptt,sizeof(MMG5_Tria));
1697 }
1698 ++nbl;
1699 }
1700 nbl = mesh->nt-nt;
1701 if ( nbl ) {
1702 fprintf(stderr,"\n ## Warning: %s: %" MMG5_PRId " extra boundaries provided."
1703 " Ignored\n",__func__,nbl);
1704 MMG5_ADD_MEM(mesh,(-nbl)*sizeof(MMG5_Tria),"triangles",return 0);
1705 MMG5_SAFE_REALLOC(mesh->tria,mesh->nt+1,nt+1,MMG5_Tria,"triangles",return 0);
1706 mesh->nt = nt;
1707 }
1708 MMG5_DEL_MEM(mesh,hashElt.item);
1709 MMG5_DEL_MEM(mesh,hashTri.item);
1710 }
1711 ntmesh +=ntpres;
1712
1715 if ( ntpres && (mesh->info.imprim > 5 || mesh->info.ddebug) )
1716 printf(" %" MMG5_PRId " triangles between 2 tetrahdra with same"
1717 " references\n",ntpres);
1718
1719 if ( mesh->nt==ntmesh && !mesh->nprism ) {
1720 for (k=1; k<=mesh->nt; k++) {
1721 ptt = &mesh->tria[k];
1722 for (i=0; i<3; i++) {
1723 if ( !mesh->info.iso ) mesh->point[ptt->v[i]].tag |= MG_BDY;
1724 }
1725 }
1726 return 1;
1727 }
1728
1729 nbl = 0;
1730 if ( !mesh->nt ) {
1731 MMG5_ADD_MEM(mesh,(ntmesh+1)*sizeof(MMG5_Tria),"triangles",return 0);
1732 MMG5_SAFE_CALLOC(mesh->tria,ntmesh+1,MMG5_Tria,return 0);
1733 }
1734 else {
1735 assert((!mesh->nprism && ntmesh>mesh->nt)||(mesh->nprism && ntmesh>=mesh->nt));
1736 if ( ntmesh > mesh->nt ) {
1737 MMG5_ADD_MEM(mesh,(ntmesh-mesh->nt)*sizeof(MMG5_Tria),"triangles",return 0);
1738 MMG5_SAFE_RECALLOC(mesh->tria,mesh->nt+1,ntmesh+1,MMG5_Tria,"triangles",return 0);
1739 nbl = ntmesh-mesh->nt;
1740 }
1741 }
1742 if ( nbl && (mesh->info.imprim > 5 || mesh->info.ddebug) )
1743 fprintf(stderr,"\n ## Warning: %s: %" MMG5_PRId " extra boundaries founded\n",
1744 __func__,nbl);
1745
1746 /* Fill missing bdy triangles */
1747 return MMG5_bdryTria(mesh,ntmesh);
1748}
1749
1750
1759 MMG5_pTetra pt,pt1;
1760 MMG5_pPrism pp;
1761 MMG5_pTria ptt;
1762 MMG5_pxTetra pxt;
1763 MMG5_pxPrism pxp;
1764 MMG5_Hash hash;
1765 MMG5_int ref,*adja,adj,k,ia,ib,ic,kt,initedg[3];
1766 int j;
1767 int16_t tag,inittag[3];
1768 int8_t i,i1,i2;
1769
1770 if ( !mesh->nt ) return 1;
1771
1772 if ( mesh->xtetra ) {
1773 if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) {
1774 fprintf(stderr,"\n ## Error: %s: mesh->xtetra must be freed.\n",__func__);
1775 }
1776 return 0;
1777 }
1778 if ( mesh->xprism ) {
1779 if ( abs(mesh->info.imprim) > 3 || mesh->info.ddebug ) {
1780 fprintf(stderr,"\n ## Error: %s: mesh->xprism must be freed.\n",__func__);
1781 }
1782 return 0;
1783 }
1784
1785 if ( ! MMG5_hashNew(mesh,&hash,0.51*mesh->nt,1.51*mesh->nt) ) return 0;
1786 for (k=1; k<=mesh->nt; k++) {
1787 ptt = &mesh->tria[k];
1788 if ( !MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k) ) return 0;
1789 }
1790
1791 mesh->xt = 0;
1792 mesh->xtmax = mesh->ntmax;
1793 assert(mesh->xtmax);
1794
1795 MMG5_ADD_MEM(mesh,(mesh->xtmax+1)*sizeof(MMG5_xTetra),"boundary tetrahedra",
1796 fprintf(stderr," Exit program.\n");
1797 return 0);
1799
1800 /* assign references to tetras faces */
1801 if ( !mesh->info.opnbdy ) {
1802 for (k=1; k<=mesh->ne; k++) {
1803 pt = &mesh->tetra[k];
1804 if ( !MG_EOK(pt) ) continue;
1805 adja = &mesh->adja[4*(k-1)+1];
1806 for (i=0; i<4; i++) {
1807 adj = adja[i] / 4;
1808 pt1 = &mesh->tetra[adj];
1809 if ( !adj || ( pt->ref != pt1->ref) ) {
1810 ia = pt->v[MMG5_idir[i][0]];
1811 ib = pt->v[MMG5_idir[i][1]];
1812 ic = pt->v[MMG5_idir[i][2]];
1813 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1814 assert(kt);
1815 if ( !pt->xt ) {
1816 mesh->xt++;
1817 if ( mesh->xt > mesh->xtmax ) {
1819 "larger xtetra table",
1820 mesh->xt--;
1821 fprintf(stderr," Exit program.\n");return 0;);
1822 }
1823 pt->xt = mesh->xt;
1824 }
1825 ptt = &mesh->tria[kt];
1826 pxt = &mesh->xtetra[pt->xt];
1827 pxt->ref[i] = ptt->ref;
1828 pxt->ftag[i] |= MG_BDY;
1829 pxt->ftag[i] |= (ptt->tag[0] & ptt->tag[1] & ptt->tag[2]);
1830 }
1831 }
1832 }
1833 }
1834 else {
1835 /* Internal triangles preservations */
1836 for (k=1; k<=mesh->ne; k++) {
1837 pt = &mesh->tetra[k];
1838 if ( !MG_EOK(pt) ) continue;
1839
1840 for (i=0; i<4; i++) {
1841 ia = pt->v[MMG5_idir[i][0]];
1842 ib = pt->v[MMG5_idir[i][1]];
1843 ic = pt->v[MMG5_idir[i][2]];
1844 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1845
1846 if ( !kt ) continue;
1847
1848 if ( !pt->xt ) {
1849 mesh->xt++;
1850 if ( mesh->xt > mesh->xtmax ) {
1852 "larger xtetra table",
1853 mesh->xt--;
1854 fprintf(stderr," Exit program.\n");return 0;);
1855 }
1856 pt->xt = mesh->xt;
1857 }
1858 ptt = &mesh->tria[kt];
1859 pxt = &mesh->xtetra[mesh->xt];
1860 pxt->ref[i] = ptt->ref;
1861 pxt->ftag[i] |= MG_BDY;
1862 pxt->ftag[i] |= (ptt->tag[0] & ptt->tag[1] & ptt->tag[2]);
1863 }
1864 }
1865 }
1866
1867 if ( !mesh->info.opnbdy ) {
1868 for (k=1; k<=mesh->ne; k++) {
1869 pt = &mesh->tetra[k];
1870 if ( !MG_EOK(pt) ) continue;
1871 if ( !pt->xt ) continue;
1872 pxt = &mesh->xtetra[pt->xt];
1873 adja = &mesh->adja[4*(k-1)+1];
1874 for (i=0; i<4; i++) {
1875 adj = adja[i] / 4;
1876 pt1 = &mesh->tetra[adj];
1877 /* Set edge tag */
1878 if ( pxt->ftag[i] ) {
1879 if ( adj && (pt->ref == pt1->ref ) ) {
1880 continue;
1881 }
1882 else {
1883 ia = pt->v[MMG5_idir[i][0]];
1884 ib = pt->v[MMG5_idir[i][1]];
1885 ic = pt->v[MMG5_idir[i][2]];
1886 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1887 ptt = &mesh->tria[kt];
1888
1889 /* Set flag to know if tetra has the same orientation than the
1890 * triangle */
1891 if ( ptt->v[0] == ia && ptt->v[1] == ib && ptt->v[2] == ic ) {
1892 MG_SET(pxt->ori,i);
1893 for (j=0; j<3; j++) {
1894 tag = pxt->ftag[i] | ptt->tag[j];
1895 if ( tag ) {
1896 if ( !MMG5_settag(mesh,k,MMG5_iarf[i][j],tag,ptt->edg[j]) )
1897 return 0;
1898 }
1899 }
1900 }
1901 else
1902 MG_CLR(pxt->ori,i);
1903 }
1904 }
1905 }
1906 }
1907 }
1908 else {
1909 for (k=1; k<=mesh->ne; k++) {
1910 pt = &mesh->tetra[k];
1911 if ( !MG_EOK(pt) ) continue;
1912 if ( !pt->xt ) continue;
1913 pxt = &mesh->xtetra[pt->xt];
1914 adja = &mesh->adja[4*(k-1)+1];
1915 for (i=0; i<4; i++) {
1916 adj = adja[i] / 4;
1917 pt1 = &mesh->tetra[adj];
1918
1919 ia = pt->v[MMG5_idir[i][0]];
1920 ib = pt->v[MMG5_idir[i][1]];
1921 ic = pt->v[MMG5_idir[i][2]];
1922 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
1923
1924 if ( !kt ) continue;
1925
1926 ptt = &mesh->tria[kt];
1927
1928 /* Set flag to know if tetra has the same orientation than the triangle
1929 * + force the triangle numbering to match the tetra face numbering */
1930 if ( adj ) {
1931 for ( j=0; j<3; ++j ) {
1932 i1 = MMG5_inxt2[j];
1933 i2 = MMG5_inxt2[i1];
1934 if ( ptt->v[j]==ia && ptt->v[i1]==ib && ptt->v[i2]==ic )
1935 break;
1936 }
1937 if ( j<3 ) {
1938 MG_SET(pxt->ori,i);
1939 if ( j!=0 ) {
1940 /* Triangle vertices+tag/edg reordering */
1941 ptt->v[0] = ia;
1942 ptt->v[1] = ib;
1943 ptt->v[2] = ic;
1944
1945 inittag[0] = ptt->tag[0];
1946 inittag[1] = ptt->tag[1];
1947 inittag[2] = ptt->tag[2];
1948 ptt->tag[0] = inittag[j];
1949 ptt->tag[1] = inittag[i1];
1950 ptt->tag[2] = inittag[i2];
1951
1952 initedg[0] = ptt->edg[0];
1953 initedg[1] = ptt->edg[1];
1954 initedg[2] = ptt->edg[2];
1955 ptt->edg[0] = initedg[j];
1956 ptt->edg[1] = initedg[i1];
1957 ptt->edg[2] = initedg[i2];
1958 }
1959 }
1960 else {
1961 MG_CLR(pxt->ori,i);
1962 }
1963 }
1964 else MG_SET(pxt->ori,i);
1965
1966 /* Set edge tag */
1967 if ( pxt->ftag[i] ) {
1968 if ( adj && ( (pt->ref < pt1->ref) || !MG_GET(pxt->ori,i) ) ) {
1969 continue;
1970 }
1971 else {
1972 for (j=0; j<3; j++) {
1973 tag = pxt->ftag[i] | ptt->tag[j];
1974 if ( tag ) {
1975 if ( !MMG5_settag(mesh,k,MMG5_iarf[i][j],tag,ptt->edg[j]) )
1976 return 0;
1977 }
1978 }
1979 }
1980 }
1981 }
1982 }
1983 }
1984
1985 if ( !mesh->nprism ) {
1986 MMG5_DEL_MEM(mesh,hash.item);
1987 return 1;
1988 }
1989
1990 mesh->xpr = 0;
1991 MMG5_ADD_MEM(mesh,(mesh->nprism+1)*sizeof(MMG5_xPrism),"boundary prisms",
1992 fprintf(stderr," Exit program.\n");
1993 return 0);
1995
1996 /* assign references to prism faces */
1997 for (k=1; k<=mesh->nprism; k++) {
1998 pp = &mesh->prism[k];
1999 if ( !MG_EOK(pp) ) continue;
2000 adja = &mesh->adjapr[5*(k-1)+1];
2001 for (i=0; i<2; i++) {
2002 adj = adja[i] / 5;
2003 if ( adj<0 ) {
2004 ref = mesh->tetra[MMG5_abs(adj)].ref;
2005 } else {
2006 ref = mesh->prism[adj].ref;
2007 }
2008 if ( adj && (pp->ref == ref) ) continue;
2009
2010 ia = pp->v[MMG5_idir_pr[i][0]];
2011 ib = pp->v[MMG5_idir_pr[i][1]];
2012 ic = pp->v[MMG5_idir_pr[i][2]];
2013 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2014 assert(kt);
2015 if ( !pp->xpr ) {
2016 mesh->xpr++;
2017 pp->xpr = mesh->xpr;
2018 }
2019 ptt = &mesh->tria[kt];
2020 pxp = &mesh->xprism[mesh->xpr];
2021 pxp->ref[i] = ptt->ref;
2022 pxp->ftag[i] |= MG_BDY;
2023 pxp->ftag[i] |= (ptt->tag[0] & ptt->tag[1] & ptt->tag[2]);
2024
2025 for (j=0; j<3; j++) {
2026 pxp->tag[MMG5_iarf[i][j]] |= pxp->ftag[i] | ptt->tag[j];
2027 pxp->edg[MMG5_iarf[i][j]] = ptt->edg[j];
2028 }
2029 }
2030 }
2031 MMG5_ADD_MEM(mesh,(mesh->xpr-mesh->nprism)*sizeof(MMG5_xPrism),"boundary prisms",
2032 fprintf(stderr," Exit program.\n");
2033 return 0);
2035 "boundary prisms",return 0);
2036
2037 MMG5_DEL_MEM(mesh,hash.item);
2038 return 1;
2039}
2040
2059 MMG5_pTetra pt;
2060 MMG5_pTria ptt;
2061 MMG5_pxTetra pxt;
2062 MMG5_Hash hash;
2063 MMG5_int ia,ib,ic,k,kt;
2064 int j;
2065 int16_t tag;
2066 int8_t i;
2067
2068 if ( !mesh->nt ) return 1;
2069 if ( !MMG5_hashNew(mesh,&hash,0.51*mesh->nt,1.51*mesh->nt) ) return 0;
2070 for (k=1; k<=mesh->nt; k++) {
2071 ptt = &mesh->tria[k];
2072 if ( !MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k) ) {
2073 MMG5_DEL_MEM(mesh,hash.item);
2074 return 0;
2075 }
2076 }
2077
2078 for (k=1; k<=mesh->ne; k++) {
2079 pt = &mesh->tetra[k];
2080 if ( !MG_EOK(pt) ) continue;
2081 if ( pt->tag & MG_REQ ) {
2082 mesh->point[mesh->tetra[k].v[0]].tag |= MG_REQ;
2083 mesh->point[mesh->tetra[k].v[1]].tag |= MG_REQ;
2084 mesh->point[mesh->tetra[k].v[2]].tag |= MG_REQ;
2085 mesh->point[mesh->tetra[k].v[3]].tag |= MG_REQ;
2086 if ( !MMG5_settag(mesh,k,0,MG_REQ,0) ) return 0;
2087 if ( !MMG5_settag(mesh,k,1,MG_REQ,0) ) return 0;
2088 if ( !MMG5_settag(mesh,k,2,MG_REQ,0) ) return 0;
2089 if ( !MMG5_settag(mesh,k,3,MG_REQ,0) ) return 0;
2090 if ( !MMG5_settag(mesh,k,4,MG_REQ,0) ) return 0;
2091 if ( !MMG5_settag(mesh,k,5,MG_REQ,0) ) return 0;
2092 mesh->point[mesh->tetra[k].v[0]].tag &= ~MG_NOSURF;
2093 mesh->point[mesh->tetra[k].v[1]].tag &= ~MG_NOSURF;
2094 mesh->point[mesh->tetra[k].v[2]].tag &= ~MG_NOSURF;
2095 mesh->point[mesh->tetra[k].v[3]].tag &= ~MG_NOSURF;
2096 if ( !MMG5_deltag(mesh,k,0,MG_NOSURF) ) return 0;
2097 if ( !MMG5_deltag(mesh,k,1,MG_NOSURF) ) return 0;
2098 if ( !MMG5_deltag(mesh,k,2,MG_NOSURF) ) return 0;
2099 if ( !MMG5_deltag(mesh,k,3,MG_NOSURF) ) return 0;
2100 if ( !MMG5_deltag(mesh,k,4,MG_NOSURF) ) return 0;
2101 if ( !MMG5_deltag(mesh,k,5,MG_NOSURF) ) return 0;
2102 }
2103
2104 if ( !pt->xt ) continue;
2105 pxt = &mesh->xtetra[pt->xt];
2106
2107 for (i=0; i<4; i++) {
2108 /* Set edge tag */
2109 if ( ! MG_GET(pxt->ori,i) ) continue;
2110 if ( pxt->ftag[i] & MG_BDY ) {
2111 ia = pt->v[MMG5_idir[i][0]];
2112 ib = pt->v[MMG5_idir[i][1]];
2113 ic = pt->v[MMG5_idir[i][2]];
2114 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2115 assert(kt);
2116 ptt = &mesh->tria[kt];
2117 if ( pt->tag & MG_REQ ) {
2118 pxt->ftag[i] |= MG_REQ;
2119 ptt->tag[0] = MG_REQ;
2120 ptt->tag[1] = MG_REQ;
2121 ptt->tag[2] = MG_REQ;
2122 pxt->ftag[i] &= ~MG_NOSURF;
2123 ptt->tag[0] &= ~MG_NOSURF;
2124 ptt->tag[1] &= ~MG_NOSURF;
2125 ptt->tag[2] &= ~MG_NOSURF;
2126 }
2127 for ( j=0; j<3; j++ ) {
2128 tag = ptt->tag[j];
2129 if ( tag || ptt->edg[j] ) {
2130 if ( !MMG5_settag(mesh,k,MMG5_iarf[i][j],tag,ptt->edg[j]) )
2131 return 0;
2132 }
2133 }
2134 }
2135 }
2136 }
2137 MMG5_DEL_MEM(mesh,hash.item);
2138 return 1;
2139}
2140
2150 MMG5_pTetra pt,pt1;
2151 MMG5_pTria ptt;
2152 MMG5_Hash hash;
2153 MMG5_int *adja,adj,k,kt,ia,ib,ic,nf;
2154 int8_t i;
2155
2156 if ( !mesh->nt ) return 1;
2157
2158 /* store triangles temporarily */
2159 if ( !MMG5_hashNew(mesh,&hash,MG_MAX(0.51*mesh->nt,100),MG_MAX(1.51*mesh->nt,300)) )
2160 return 0;
2161
2162 for (k=1; k<=mesh->nt; k++) {
2163 ptt = &mesh->tria[k];
2164 if ( !MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k) ) {
2165 MMG5_DEL_MEM(mesh,hash.item);
2166 return 0;
2167 }
2168 }
2169
2170 /* check orientation */
2171 nf = 0;
2172 for (k=1; k<=mesh->ne; k++) {
2173 pt = &mesh->tetra[k];
2174 if ( !MG_EOK(pt) ) continue;
2175 adja = &mesh->adja[4*(k-1)+1];
2176 for (i=0; i<4; i++) {
2177 adj = adja[i] / 4;
2178 pt1 = &mesh->tetra[adj];
2179
2180 if ( adj && (pt->ref <= pt1->ref || pt->ref == MG_PLUS) )
2181 continue;
2182
2183 ia = pt->v[MMG5_idir[i][0]];
2184 ib = pt->v[MMG5_idir[i][1]];
2185 ic = pt->v[MMG5_idir[i][2]];
2186 kt = MMG5_hashGetFace(&hash,ia,ib,ic);
2187 if ( kt ) {
2188 /* check orientation */
2189 ptt = &mesh->tria[kt];
2190 if ( ptt->v[0] == ia && ptt->v[1] == ib && ptt->v[2] == ic )
2191 continue;
2192 else {
2193 ptt->v[0] = ia;
2194 ptt->v[1] = ib;
2195 ptt->v[2] = ic;
2196 nf++;
2197 }
2198 }
2199 }
2200 }
2201 if ( mesh->info.ddebug && nf > 0 )
2202 fprintf(stdout," ## %" MMG5_PRId " faces reoriented\n",nf);
2203
2204 MMG5_DEL_MEM(mesh,hash.item);
2205
2206 return 1;
2207}
int ier
MMG5_pMesh * mesh
int MMG5_settag(MMG5_pMesh mesh, MMG5_int start, int ia, int16_t tag, int edg)
Definition boulep_3d.c:1228
int MMG5_deltag(MMG5_pMesh mesh, MMG5_int start, int ia, int16_t tag)
Definition boulep_3d.c:1344
void MMG3D_coquilFaceSecondLoopInit(MMG5_pMesh mesh, MMG5_int piv, int8_t *iface, int8_t *ia, int64_t *list, int *ilist, MMG5_int *it1, MMG5_int *pradj, MMG5_int *adj)
Definition boulep_3d.c:1787
int MMG3D_coquilFaceFirstLoop(MMG5_pMesh mesh, MMG5_int start, MMG5_int na, MMG5_int nb, int8_t iface, int8_t ia, int64_t *list, int *ilist, MMG5_int *it1, MMG5_int *it2, MMG5_int *piv, MMG5_int *adj, int8_t *hasadja, int *nbdy, int silent)
Definition boulep_3d.c:1686
void MMG5_coquilFaceErrorMessage(MMG5_pMesh mesh, MMG5_int k1, MMG5_int k2)
Definition boulep_3d.c:1613
int16_t MMG5_openCoquilTravel(MMG5_pMesh mesh, MMG5_int na, MMG5_int nb, MMG5_int *adj, MMG5_int *piv, int8_t *iface, int8_t *i)
Definition boulep_3d.c:2011
int MMG5_boulernm(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int start, int ip, MMG5_int *ng, MMG5_int *nr, MMG5_int *nm)
Definition boulep_3d.c:455
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:526
int MMG5_paktet(MMG5_pMesh mesh)
Definition hash_3d.c:50
int MMG3D_hashTetra(MMG5_pMesh mesh, int pack)
Definition hash_3d.c:122
int MMG5_hGeom(MMG5_pMesh mesh)
Definition hash_3d.c:1036
int MMG5_hNew(MMG5_pMesh mesh, MMG5_HGeom *hash, MMG5_int hsiz, MMG5_int hmax)
Definition hash_3d.c:1008
int MMG3D_hashPrism(MMG5_pMesh mesh)
Definition hash_3d.c:245
static int MMG5_bdryTria(MMG5_pMesh mesh, MMG5_int ntmesh)
Definition hash_3d.c:1191
MMG5_int MMG5_hashGetFace(MMG5_Hash *hash, MMG5_int ia, MMG5_int ib, MMG5_int ic)
Definition hash_3d.c:84
int MMG5_hGet(MMG5_HGeom *hash, MMG5_int a, MMG5_int b, MMG5_int *ref, int16_t *tag)
Definition hash_3d.c:932
int MMG5_chkBdryTria(MMG5_pMesh mesh)
Definition hash_3d.c:1453
int MMG5_bdrySet(MMG5_pMesh mesh)
Definition hash_3d.c:1758
static int MMG5_setEdgeNmTag(MMG5_pMesh mesh, MMG5_Hash *hash)
Definition hash_3d.c:470
int8_t ddb
int MMG5_bdryUpdate(MMG5_pMesh mesh)
Definition hash_3d.c:2058
int MMG5_setNmTag(MMG5_pMesh mesh, MMG5_Hash *hash)
Definition hash_3d.c:741
int MMG3D_hashTria(MMG5_pMesh mesh, MMG5_Hash *hash)
Definition hash_3d.c:763
static int MMG5_setVertexNmTag(MMG5_pMesh mesh)
Definition hash_3d.c:638
int MMG5_hashPop(MMG5_Hash *hash, MMG5_int a, MMG5_int b)
Definition hash_3d.c:775
int MMG5_hTag(MMG5_HGeom *hash, MMG5_int a, MMG5_int b, MMG5_int ref, int16_t tag)
Definition hash_3d.c:839
int MMG5_hPop(MMG5_HGeom *hash, MMG5_int a, MMG5_int b, MMG5_int *ref, int16_t *tag)
Definition hash_3d.c:872
int MMG5_bdryPerm(MMG5_pMesh mesh)
Definition hash_3d.c:2149
int MMG5_hEdge(MMG5_pMesh mesh, MMG5_HGeom *hash, MMG5_int a, MMG5_int b, MMG5_int ref, int16_t tag)
Definition hash_3d.c:965
#define MMG5_KC
Definition hash_3d.c:38
API headers for the mmg3d library.
#define MMG3D_LMAX
Definition libmmg3d.h:58
MMG5_int MMG3D_indPt(MMG5_pMesh mesh, MMG5_int kp)
Definition tools_3d.c:916
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:71
int MMG5_isLevelSet(MMG5_pMesh mesh, MMG5_int ref0, MMG5_int ref1)
Definition mmg2.c:477
#define MG_REQ
#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 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_CRN
#define MG_BDY
#define MG_NOSURF
#define MG_NOM
#define MMG5_KA
#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 a MMG mesh.
MMG5_int b
MMG5_int ref
int16_t tag
MMG5_int a
Hash table to store geometric edges.
MMG5_int max
MMG5_hgeom * geom
MMG5_int siz
MMG5_int nxt
Identic as MMG5_HGeom but use MMG5_hedge to store edges instead of MMG5_hgeom (memory economy).
MMG5_int nxt
MMG5_hedge * item
MMG5_int siz
int8_t iso
int8_t ddebug
MMG5_int isoref
uint8_t nosurf
MMG mesh structure.
MMG5_int ntmax
MMG5_Info info
MMG5_int * adjapr
MMG5_int xt
MMG5_int ne
MMG5_pPoint point
MMG5_int xpr
MMG5_int * adja
MMG5_pPrism prism
MMG5_int xtmax
MMG5_int nemax
MMG5_int nenil
MMG5_HGeom htab
MMG5_int namax
MMG5_int base
MMG5_pTetra tetra
MMG5_pxPrism xprism
MMG5_int nt
MMG5_pTria tria
MMG5_int np
MMG5_pEdge edge
MMG5_pxTetra xtetra
MMG5_int nprism
MMG5_int na
MMG5_int * adjt
Structure to store points of a MMG mesh.
int16_t tag
MMG5_int flag
MMG5_int v[6]
MMG5_int ref
MMG5_int xpr
MMG5_int v[4]
MMG5_int xt
MMG5_int ref
int16_t tag
MMG5_int edg[3]
int16_t tag[3]
MMG5_int ref
MMG5_int v[3]
MMG5_int cc
Used to hash edges (memory economy compared to MMG5_hgeom).
MMG5_int s
MMG5_int b
MMG5_int a
MMG5_int k
MMG5_int nxt
Cell of the hash table of geom edges.
MMG5_int ref
int16_t tag
MMG5_int b
MMG5_int nxt
MMG5_int a
Structure to store the surface prism of a MMG mesh.
int16_t ftag[5]
int16_t tag[9]
MMG5_int edg[9]
MMG5_int ref[5]
Structure to store the surface tetrahedra of a MMG mesh.
int16_t ftag[4]
int16_t tag[6]
MMG5_int edg[6]
MMG5_int ref[4]