Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
analys_s.c
Go to the documentation of this file.
1/* =============================================================================
2** This file is part of the mmg software package for the tetrahedral
3** mesh modification.
4** Copyright (c) Bx INP/CNRS/Inria/UBordeaux/UPMC, 2004-
5**
6** mmg is free software: you can redistribute it and/or modify it
7** under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation, either version 3 of the License, or
9** (at your option) any later version.
10**
11** mmg is distributed in the hope that it will be useful, but WITHOUT
12** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13** FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14** License for more details.
15**
16** You should have received a copy of the GNU Lesser General Public
17** License and of the GNU General Public License along with mmg (in
18** files COPYING.LESSER and COPYING). If not, see
19** <http://www.gnu.org/licenses/>. Please read their terms carefully and
20** use this copy of the mmg distribution only if you accept them.
21** =============================================================================
22*/
23
36#include "libmmgs_private.h"
37#include "mmgcommon_private.h"
38
48 MMG5_pTria pt,pt1;
49 MMG5_int *adja,*adjb,adji1,adji2,*pile,iad,ipil,ip1,ip2,gen;
50 MMG5_int k,kk,iel,jel,nvf,nf,nr,nt,nre,nreq,ncc,ned,ref;
51 int16_t tag;
52 int8_t i,ii,i1,i2,ii1,ii2,voy;
53
54 if ( abs(mesh->info.imprim) > 5 || mesh->info.ddebug )
55 fprintf(stdout," ** SETTING TOPOLOGY\n");
56
57 nvf = nf = ncc = ned = 0;
58
59 MMG5_SAFE_MALLOC(pile,mesh->nt+1,MMG5_int,return 0);
60
61 pile[1] = 1;
62 ipil = 1;
63
64 while ( ipil > 0 ) {
65 ncc++;
66
67 do {
68 k = pile[ipil--];
69 pt = &mesh->tria[k];
70 pt->flag = 1;
71 if ( !MG_EOK(pt) ) continue;
72
73 pt->cc = ncc;
74 adja = &mesh->adja[3*(k-1)+1];
75 for (i=0; i<3; i++) {
76 i1 = MMG5_inxt2[i];
77 i2 = MMG5_iprv2[i];
78 ip1 = pt->v[i1];
79 ip2 = pt->v[i2];
80
81 if ( !mesh->point[ip1].tmp ) mesh->point[ip1].tmp = ++nvf;
82 if ( !mesh->point[ip2].tmp ) mesh->point[ip2].tmp = ++nvf;
83
84 if ( MG_EDG(pt->tag[i]) || pt->tag[i] & MG_REQ ) {
85 mesh->point[ip1].tag |= pt->tag[i];
86 mesh->point[ip2].tag |= pt->tag[i];
87 }
88
89 /* open boundary */
90 if ( !adja[i] ) {
91 pt->tag[i] |= MG_GEO;
92 mesh->point[ip1].tag |= MG_GEO;
93 mesh->point[ip2].tag |= MG_GEO;
94 ned++;
95 continue;
96 }
97
98 kk = adja[i] / 3;
99 ii = adja[i] % 3;
100 if ( kk > k ) ned++;
101
102 /* store adjacent */
103 pt1 = &mesh->tria[kk];
104
105 /* correct edge tag */
106 if ( (pt->tag[i] & MG_NOM) && !(pt1->tag[ii] & MG_NOM) ) {
107 pt1->tag[ii] = pt->tag[i];
108 pt1->edg[ii] = pt->edg[i];
109 mesh->point[ip1].tag |= MG_NOM;
110 mesh->point[ip2].tag |= MG_NOM;
111 continue;
112 }
113 if ( (pt1->tag[ii] & MG_NOM) && !(pt->tag[i] & MG_NOM) ) {
114 pt->tag[i] = pt1->tag[ii];
115 pt->edg[i] = pt1->edg[ii];
116 mesh->point[ip1].tag |= MG_NOM;
117 mesh->point[ip2].tag |= MG_NOM;
118 continue;
119 }
120
121 if ( MMG5_abs(pt1->ref) != MMG5_abs(pt->ref) ) {
122 pt->tag[i] |= MG_REF;
123 pt1->tag[ii] |= MG_REF;
124 mesh->point[ip1].tag |= MG_REF;
125 mesh->point[ip2].tag |= MG_REF;
126 }
127
128 /* Do not treat adjacent through a non-manifold edge */
129 if ( pt1->tag[ii] & MG_NOM ) {
130 continue;
131 }
132
133 /* store adjacent */
134 if ( !pt1->flag ) {
135 pt1->flag = 1;
136 pile[++ipil] = kk;
137 }
138
139 /* check orientation */
140 ii1 = MMG5_inxt2[ii];
141 ii2 = MMG5_iprv2[ii];
142 if ( pt1->v[ii1] == ip1 ) {
143 /* Moebius strip */
144 assert ( pt1->base );
145 if ( pt1->base < 0 ) {
146 pt1->ref = -MMG5_abs(pt1->ref);
147 /* Add MG_NOM flag because it allows neighbours to have non
148 * consistent orientations */
149 pt->tag[i] |= MG_REF + MG_NOM;
150 pt1->tag[ii] |= MG_REF + MG_NOM;
151 }
152 /* flip orientation */
153 else {
154 pt1->base = -pt1->base;
155 pt1->v[ii1] = ip2;
156 pt1->v[ii2] = ip1;
157
158 /* update adj */
159 iad = 3*(kk-1)+1;
160 adjb = &mesh->adja[iad];
161 adji1 = mesh->adja[iad+ii1];
162 adji2 = mesh->adja[iad+ii2];
163 adjb[ii1] = adji2;
164 adjb[ii2] = adji1;
165
166 /* modif tag + ref */
167 tag = pt1->tag[ii1];
168 pt1->tag[ii1] = pt1->tag[ii2];
169 pt1->tag[ii2] = tag;
170 ref = pt1->edg[ii1];
171 pt1->edg[ii1] = pt1->edg[ii2];
172 pt1->edg[ii2] = ref;
173
174 /* modif voyeurs */
175 if ( adjb[ii1] ) {
176 iel = adjb[ii1] / 3;
177 voy = adjb[ii1] % 3;
178 mesh->adja[3*(iel-1)+1+voy] = 3*kk + ii1;
179 }
180 if ( adjb[ii2] ) {
181 iel = adjb[ii2] / 3;
182 voy = adjb[ii2] % 3;
183 mesh->adja[3*(iel-1)+1+voy] = 3*kk + ii2;
184 }
185 nf++;
186 }
187 }
188 else {
189 /* Mark triangles that have a consistent orientation with their
190 * neighbours */
191 pt1->base = -pt1->base;
192 }
193 }
194 }
195 while ( ipil > 0 );
196
197 /* find next unmarked triangle */
198 ipil = 0;
199 for (kk=1; kk<=mesh->nt; kk++) {
200 pt = &mesh->tria[kk];
201 if ( MG_EOK(pt) && (pt->cc == 0) ) {
202 ipil = 1;
203 pile[ipil] = kk;
204 pt->flag = 1;
205 break;
206 }
207 }
208 }
209
210 /* bilan */
211 nr = nre = nreq = nt = 0;
212 for (k=1; k<=mesh->nt; k++) {
213 pt = &mesh->tria[k];
214 if ( !MG_EOK(pt) ) continue;
215 nt++;
216 adja = &mesh->adja[3*(k-1)+1];
217 for (i=0; i<3; i++) {
218 if ( ( !MG_EDG(pt->tag[i]) ) && ( !(pt->tag[i] & MG_REQ) ) ) continue;
219
220 jel = adja[i] / 3;
221 if ( !jel || jel > k ) {
222 if ( pt->tag[i] & MG_GEO ) nr++;
223 if ( pt->tag[i] & MG_REF ) nre++;
224 if ( pt->tag[i] & MG_REQ ) nreq++;
225 }
226 }
227 }
228
229 if ( mesh->info.ddebug ) {
230 fprintf(stdout," a- ridges: %" MMG5_PRId " found.\n",nr);
231 fprintf(stdout," a- requir: %" MMG5_PRId " found.\n",nreq);
232 fprintf(stdout," a- connex: %" MMG5_PRId " connected component(s)\n",ncc);
233 fprintf(stdout," a- orient: %" MMG5_PRId " flipped\n",nf);
234 }
235 else if ( abs(mesh->info.imprim) > 3 ) {
236 gen = (2 - nvf + ned - nt) / 2;
237 fprintf(stdout," Connected component: %" MMG5_PRId ", genus: %" MMG5_PRId ", reoriented: %" MMG5_PRId "\n",ncc,gen,nf);
238 fprintf(stdout," Edges: %" MMG5_PRId ", tagged: %" MMG5_PRId ", ridges: %" MMG5_PRId ", required: %" MMG5_PRId ", refs: %" MMG5_PRId "\n",
239 ned,nr+nre+nreq,nr,nreq,nre);
240 }
241
242 MMG5_SAFE_FREE(pile);
243 return 1;
244}
245
254 MMG5_pTria pt;
255 MMG5_pPoint p0;
256 MMG5_int k,np,numt,iel,jel,nmp,*adja;
257 int8_t i0,i1,i,jp;
258
259 nmp = 0;
260 /* Initialize point flags */
261 for (k=1; k<=mesh->np; k++)
262 mesh->point[k].s = 0;
263
264 for (k=1; k<=mesh->nt; k++) {
265 pt = &mesh->tria[k];
266 if ( !MG_EOK(pt) ) continue;
267
268 for (i=0; i<3; i++) {
269 np = pt->v[i];
270 p0 = &mesh->point[np];
271 if ( !p0->s ) p0->s = k;
272 }
273 }
274
275 for (k=1; k<=mesh->nt; k++) {
276 pt = &mesh->tria[k];
277 if ( !MG_EOK(pt) ) continue;
278
279 for (i=0; i<3; i++) {
280 np = pt->v[i];
281 p0 = &mesh->point[np];
282 numt = p0->s;
283 if ( k == numt ) continue;
284 jel = k;
285 jp = i;
286
287 /* Unfold ball of np, until numt is reached */
288 do {
289 iel = jel;
290 i0 = jp;
291 i1 = MMG5_inxt2[i0];
292 adja = &mesh->adja[3*(iel-1)+1];
293 jel = adja[i1] / 3;
294 jp = adja[i1] % 3;
295 jp = MMG5_inxt2[jp];
296 }
297 while ( jel && (jel != numt) && (jel !=k) );
298
299 /* Ball has been completely traveled without meeting numt */
300 if ( jel == k ) {
301 if ( !(p0->tag & MG_CRN) || !(p0->tag & MG_REQ) ) {
302 nmp++;
303 // p0->tag |= MG_CRN + MG_REQ; // Algiane 2022: this line has been
304 // commented by commit 1f592c. I think that it is a mistake (some
305 // forgotten debug thing). It seems that in any case, nm points are
306 // marked as CRN and REQ when checking handles in MMGS_singul
307 }
308 continue;
309 }
310 else if ( jel == numt )
311 continue;
312
313 jel = iel;
314 jp = i0;
315
316 /* At this point, jel =0, i.e. an open boundary has been hit : travel in the opposite sense */
317 do {
318 iel = jel;
319 i0 = jp;
320 i1 = MMG5_iprv2[i0];
321 adja = &mesh->adja[3*(iel-1)+1];
322 jel = adja[i1] / 3;
323 jp = adja[i1] % 3;
324 jp = MMG5_iprv2[jp];
325 }
326 while ( jel && (jel != numt));
327
328 if ( jel != numt) {
329 if ( !(p0->tag & MG_CRN) || !(p0->tag & MG_REQ) ) {
330 p0->tag |= MG_CRN + MG_REQ;
331 nmp++;
332 }
333 }
334 }
335 }
336
337 /* reset point flags */
338 for (k=1; k<=mesh->np; k++)
339 mesh->point[k].s = 0;
340
341 if ( nmp && abs(mesh->info.imprim) > 4 )
342 fprintf(stdout," ## %" MMG5_PRId " non manifold points detected\n",nmp);
343}
344
346/* static int delbad(MMG5_pMesh mesh) { */
347/* MMG5_pTria pt; */
348/* MMG5_pPoint p[3]; */
349/* double s,kal,declic,ux,uy,uz,vx,vy,vz; */
350/* MMG5_int *adja,k,iel,nd,ndd; */
351/* int it; */
352/* int8_t i,ia,i1,i2,j,typ; */
353
354/* it = ndd = 0; */
355/* declic = MMGS_BADKAL / MMGS_ALPHAD; */
356
357/* do { */
358/* nd = 0; */
359/* for (k=1; k<=mesh->nt; k++) { */
360/* pt = &mesh->tria[k]; */
361/* if ( !MG_EOK(pt) ) continue; */
362
363/* kal = MMG5_calelt(mesh,NULL,pt); */
364/* if ( kal > declic ) continue; */
365
366/* p[0] = &mesh->point[pt->v[0]]; */
367/* p[1] = &mesh->point[pt->v[1]]; */
368/* p[2] = &mesh->point[pt->v[2]]; */
369/* adja = &mesh->adja[3*(k-1)+1]; */
370/* typ = typelt(p,&ia); */
371
372/* /\* needle *\/ */
373/* if ( typ == 1 ) { */
374/* if ( litcol(mesh,k,ia,kal) ) { */
375/* nd++; */
376/* continue; */
377/* } */
378/* } */
379/* /\* obtuse *\/ */
380/* else if ( typ == 2 ) { */
381/* /\* delete boundary elt *\/ */
382/* if ( !adja[ia] ) { */
383/* /\* update point coordinates on ridge *\/ */
384/* i1 = MMG5_inxt2[ia]; */
385/* i2 = MMG5_iprv2[ia]; */
386/* p[0] = &mesh->point[pt->v[ia]]; */
387/* p[1] = &mesh->point[pt->v[i1]]; */
388/* p[2] = &mesh->point[pt->v[i2]]; */
389/* ux = p[2]->c[0] - p[1]->c[0]; */
390/* uy = p[2]->c[1] - p[1]->c[1]; */
391/* uz = p[2]->c[2] - p[1]->c[2]; */
392/* vx = p[0]->c[0] - p[1]->c[0]; */
393/* vy = p[0]->c[1] - p[1]->c[1]; */
394/* vz = p[0]->c[2] - p[1]->c[2]; */
395/* s = (ux*vx + uy*vy + uz*vz) / sqrt(ux*ux + uy*uy + uz*uz); */
396/* p[0]->c[0] = vx - s*ux; */
397/* p[0]->c[1] = vy - s*uy; */
398/* p[0]->c[2] = vz - s*uz; */
399
400/* if ( !delElt(mesh,k) ) return 0; */
401/* nd++; */
402/* continue; */
403/* } */
404/* if ( litswp(mesh,k,ia,kal) || litcol(mesh,k,ia,kal) ) { */
405/* nd++; */
406/* continue; */
407/* } */
408/* } */
409
410/* /\* brute force to improve *\/ */
411/* for (i=0; i<3; i++) { */
412/* if ( litswp(mesh,k,i,kal) || litcol(mesh,k,i,kal) ) { */
413/* nd++; */
414/* break; */
415/* } */
416/* else if ( adja[i] ) { */
417/* iel = adja[i] / 3; */
418/* j = adja[i] % 3; */
419/* if ( litcol(mesh,iel,j,kal) ) { */
420/* nd++; */
421/* break; */
422/* } */
423/* } */
424/* } */
425/* } */
426/* ndd += nd; */
427/* if ( nd && (mesh->info.ddebug || mesh->info.imprim < -1) ) fprintf(stdout," %" MMG5_PRId " improved\n",nd); */
428/* } */
429/* while ( nd > 0 && ++it < 5 ); */
430
431/* if ( abs(mesh->info.imprim) > 4 ) */
432/* fprintf(stdout," %" MMG5_PRId " bad elements improved\n",ndd); */
433
434/* return 1; */
435/* } */
436
437
445static int setdhd(MMG5_pMesh mesh) {
446 MMG5_pTria pt,pt1;
447 double n1[3],n2[3],dhd;
448 MMG5_int *adja,k,kk,nr;
449 int8_t i,ii,i1,i2;
450
451 nr = 0;
452 for (k=1; k<=mesh->nt; k++) {
453 pt = &mesh->tria[k];
454 if ( !MG_EOK(pt) ) continue;
455
456 /* triangle normal */
457 MMG5_nortri(mesh,pt,n1);
458 adja = &mesh->adja[3*(k-1)+1];
459 for (i=0; i<3; i++) {
460 if ( pt->tag[i] & MG_GEO ) continue;
461 kk = adja[i] / 3;
462 ii = adja[i] % 3;
463
464 /* check angle w. neighbor */
465 if ( k < kk ) {
466 pt1 = &mesh->tria[kk];
467 MMG5_nortri(mesh,pt1,n2);
468 dhd = n1[0]*n2[0] + n1[1]*n2[1] + n1[2]*n2[2];
469 if ( dhd <= mesh->info.dhd ) {
470 pt->tag[i] |= MG_GEO;
471 pt1->tag[ii] |= MG_GEO;
472 i1 = MMG5_inxt2[i];
473 i2 = MMG5_inxt2[i1];
474 mesh->point[pt->v[i1]].tag |= MG_GEO;
475 mesh->point[pt->v[i2]].tag |= MG_GEO;
476 nr++;
477 }
478 }
479 }
480 }
481
482 if ( abs(mesh->info.imprim) > 4 && nr > 0 )
483 fprintf(stdout," %" MMG5_PRId " ridges updated\n",nr);
484
485 return 1;
486}
487
497 MMG5_pTria pt;
498 MMG5_pPoint ppt,p1,p2;
499 double ux,uy,uz,vx,vy,vz,dd;
500 MMG5_int list[MMG5_TRIA_LMAX+2],listref[MMG5_TRIA_LMAX+2],k,nc,nre;
501 int xp,nr,ns;
502 int8_t i;
503
504 nre = nc = 0;
505 for (k=1; k<=mesh->nt; k++) {
506 pt = &mesh->tria[k];
507 if ( !MG_EOK(pt) ) continue;
508
509 for (i=0; i<3; i++) {
510 ppt = &mesh->point[pt->v[i]];
511 ppt->s++;
512 if ( !MG_VOK(ppt) || ( ppt->tag & MG_CRN ) || ( ppt->tag & MG_NOM ) ) continue;
513 else if ( MG_EDG(ppt->tag) ) {
514 ns = MMG5_bouler(mesh,mesh->adja,k,i,list,listref,&xp,&nr, MMG5_TRIA_LMAX);
515
516 if ( !ns ) continue;
517 if ( (xp+nr) > 2 ) {
518 ppt->tag |= MG_CRN + MG_REQ;
519 nre++;
520 nc++;
521 }
522 else if ( (xp == 1) && (nr == 1) ) {
523 ppt->tag |= MG_REQ;
524 nre++;
525 }
526 else if ( xp == 1 && !nr ){
527 ppt->tag |= MG_CRN + MG_REQ;
528 nre++;
529 nc++;
530 }
531 else if ( nr == 1 && !xp ){
532 ppt->tag |= MG_CRN + MG_REQ;
533 nre++;
534 nc++;
535 }
536 /* check ridge angle */
537 else {
538 p1 = &mesh->point[list[1]];
539 p2 = &mesh->point[list[2]];
540 ux = p1->c[0] - ppt->c[0];
541 uy = p1->c[1] - ppt->c[1];
542 uz = p1->c[2] - ppt->c[2];
543 vx = p2->c[0] - ppt->c[0];
544 vy = p2->c[1] - ppt->c[1];
545 vz = p2->c[2] - ppt->c[2];
546 dd = (ux*ux + uy*uy + uz*uz) * (vx*vx + vy*vy + vz*vz);
547 if ( fabs(dd) > MMG5_EPSD ) {
548 dd = (ux*vx + uy*vy + uz*vz) / sqrt(dd);
549 if ( dd > -mesh->info.dhd ) {
550 ppt->tag |= MG_CRN;
551 nc++;
552 }
553 }
554 }
555 }
556 }
557 }
558
559 /* check for handle */
560 for (k=1; k<=mesh->nt; k++) {
561 pt = &mesh->tria[k];
562 if ( !MG_EOK(pt) ) continue;
563 for (i=0; i<3; i++) {
564 ppt = &mesh->point[pt->v[i]];
565 if ( !ppt->s ) continue;
566 int8_t dummy;
567 nr = MMG5_boulet(mesh,k,i,list,1,&dummy);
568 if ( nr != ppt->s ) {
569 ppt->tag |= MG_CRN + MG_REQ;
570 ppt->s = 0;
571 nc++;
572 }
573 }
574 }
575
576 /* reset the ppt->s tag */
577 for (k=1; k<=mesh->np; ++k) {
578 mesh->point[k].s = 0;
579 }
580
581 if ( abs(mesh->info.imprim) > 3 && nre > 0 )
582 fprintf(stdout," %" MMG5_PRId " corners, %" MMG5_PRId " singular points detected\n",nc,nre);
583 return 1;
584}
585
599static int norver(MMG5_pMesh mesh) {
600 MMG5_pTria pt;
601 MMG5_pPoint ppt;
602 MMG5_pxPoint go;
603 double n[3],dd;
604 MMG5_int *adja,k,kk,ier,xp,nn,nt,nf,nnr;
605 int8_t i,ii,i1;
606
607 if ( abs(mesh->info.imprim) > 4 || mesh->info.ddebug )
608 fprintf(stdout," ** DEFINING GEOMETRY\n");
609
610 /* 1. process C1 vertices, normals */
611 nn = xp = nt = nf = nnr = 0;
612 ++mesh->base;
613 for (k=1; k<=mesh->nt; k++) {
614 pt = &mesh->tria[k];
615 if ( !MG_EOK(pt) ) continue;
616
617 for (i=0; i<3; i++) {
618 ppt = &mesh->point[pt->v[i]];
619
620 if ( MS_SIN(ppt->tag) || MG_EDG(ppt->tag) ) {
621 if ( mesh->nc1 ) {
622 if ( ppt->n[0]*ppt->n[0]+ppt->n[1]*ppt->n[1]+ppt->n[2]*ppt->n[2] > 0 )
623 ++nnr;
624 }
625
626 if ( MG_EDG(ppt->tag) ) xp++;
627
628 continue;
629 }
630 else if ( ppt->flag == mesh->base ) continue;
631 else if ( mesh->nc1 ) {
632 if ( ppt->n[0]*ppt->n[0] + ppt->n[1]*ppt->n[1] + ppt->n[2]*ppt->n[2] > 0 )
633 continue;
634 }
635
636 ier = MMG5_boulen(mesh,mesh->adja,k,i,ppt->n);
637 if ( ier ) {
638 ppt->flag = mesh->base;
639 nn++;
640 }
641 else
642 nf++;
643 }
644 }
645
646 /* memory to store normals on both sides of ridges */
647 mesh->xpmax = MG_MAX(1.5*xp,MMGS_XPMAX);
648 /* no need to have more xpoint than point */
650 MMG5_ADD_MEM(mesh,(mesh->xpmax+1)*sizeof(MMG5_xPoint),"boundary points",return 0);
652
653 if ( xp ) {
654 /* 2. process C0 vertices on curves, tangents */
655 for (k=1; k<=mesh->nt; k++) {
656 pt = &mesh->tria[k];
657 if ( !MG_EOK(pt) ) continue;
658
659 adja = &mesh->adja[3*(k-1)+1];
660 for (i=0; i<3; i++) {
661 i1 = MMG5_inxt2[i];
662 ppt = &mesh->point[pt->v[i]];
663
664 if ( ppt->tag & MG_CRN || ppt->flag == mesh->base ) continue;
665 else if ( !MG_EDG(pt->tag[i1]) ) continue;
666
667 /* As we skip non-manifold point, the edge should be manifold */
668 assert ( (!(MG_NOM & pt->tag[i1])) && "Unexpected non-manifold edge" );
669
670 ier = MMG5_boulen(mesh,mesh->adja,k,i,n);
671 if ( !ier ) continue;
672
673 ++mesh->xp;
674 if(mesh->xp > mesh->xpmax){
676 "larger xpoint table",
677 mesh->xp--;
678 return 0);
679 }
680 ppt->xp = mesh->xp;
681 go = &mesh->xpoint[mesh->xp];
682 memcpy(go->n1,n,3*sizeof(double));
683
684 /* compute n2 along ridge */
685 if ( pt->tag[i1] & MG_GEO ) {
686 if ( adja[i1] ) {
687 kk = adja[i1] / 3;
688 ii = adja[i1] % 3;
689 ii = MMG5_inxt2[ii];
690
691 ier = MMG5_boulen(mesh,mesh->adja,kk,ii,n);
692 if ( !ier ) continue;
693 memcpy(go->n2,n,3*sizeof(double));
694
695 /* compute tangent as intersection of n1 + n2 */
696 ppt->n[0] = go->n1[1]*go->n2[2] - go->n1[2]*go->n2[1];
697 ppt->n[1] = go->n1[2]*go->n2[0] - go->n1[0]*go->n2[2];
698 ppt->n[2] = go->n1[0]*go->n2[1] - go->n1[1]*go->n2[0];
699 ppt->flag = mesh->base;
700 dd = ppt->n[0]*ppt->n[0] + ppt->n[1]*ppt->n[1] + ppt->n[2]*ppt->n[2];
701 if ( dd > MMG5_EPSD2 ) {
702 dd = 1.0 / sqrt(dd);
703 ppt->n[0] *= dd;
704 ppt->n[1] *= dd;
705 ppt->n[2] *= dd;
706 }
707 ++nt;
708 continue;
709 }
710 }
711
712 /* compute tgte */
713 ier = MMG5_boulec(mesh,mesh->adja,k,i,ppt->n);
714 if ( !ier ) continue;
715 dd = go->n1[0]*ppt->n[0] + go->n1[1]*ppt->n[1] + go->n1[2]*ppt->n[2];
716 ppt->n[0] -= dd*go->n1[0];
717 ppt->n[1] -= dd*go->n1[1];
718 ppt->n[2] -= dd*go->n1[2];
719 dd = ppt->n[0]*ppt->n[0] + ppt->n[1]*ppt->n[1] + ppt->n[2]*ppt->n[2];
720 if ( dd > MMG5_EPSD2 ) {
721 dd = 1.0 / sqrt(dd);
722 ppt->n[0] *= dd;
723 ppt->n[1] *= dd;
724 ppt->n[2] *= dd;
725 ppt->flag = mesh->base;
726 ++nt;
727 }
728 }
729 }
730 }
731
732 if ( abs(mesh->info.imprim) > 4 && nn+nt > 0 ) {
733 if ( nnr )
734 fprintf(stdout," %" MMG5_PRId " input normals ignored\n",nnr);
735 fprintf(stdout," %" MMG5_PRId " normals, %" MMG5_PRId " tangents updated (%" MMG5_PRId " failed)\n",nn,nt,nf);
736 }
737
738 return 1;
739}
740
754static inline int MMGS_dichotomy(MMG5_pMesh mesh, MMG5_pTria pt, MMG5_int k, double *c, double *n) {
755
756 MMG5_pPoint ppt;
757 double to,tp,t,nnew[3],p[3],o[3],result;
758 int it,maxit,pos,ier;
759
760 it = 0;
761 maxit = 5;
762 to = 0.0;
763 tp = 1.0;
764 t = 0.5;
765 pos = 0;
766
767 ppt = &mesh->point[k];
768
769 /* initial coordinates of point before regularization */
770 o[0] = ppt->c[0];
771 o[1] = ppt->c[1];
772 o[2] = ppt->c[2];
773
774 /* initial coordinates of new point */
775 p[0] = c[0];
776 p[1] = c[1];
777 p[2] = c[2];
778
779 do {
780 mesh->point[0].c[0] = o[0] + t*(p[0] - o[0]);
781 mesh->point[0].c[1] = o[1] + t*(p[1] - o[1]);
782 mesh->point[0].c[2] = o[2] + t*(p[2] - o[2]);
783
784 MMG5_nortri(mesh, pt, nnew);
785 MMG5_dotprod(3,n,nnew,&result);
786
787 if ( result <= 0.0 ) {
788 tp = t;
789 }
790 else {
791 c[0] = mesh->point[0].c[0];
792 c[1] = mesh->point[0].c[1];
793 c[2] = mesh->point[0].c[2];
794 to = t;
795 pos = 1;
796 }
797
798 t = 0.5*(to + tp);
799 }
800 while ( ++it < maxit );
801
802 if ( pos ) {
803 return 1;
804 }
805 else
806 return 0;
807}
808
818 MMG5_pTria pt;
819 MMG5_pPoint ppt,p0;
820 MMG5_Tria tnew;
821 double *tabl,c[3],n[3],nnew[3],*cptr,lm1,lm2,cx,cy,cz,res0,res,result;
822 int i,it,nit,ilist,noupdate,ier;
823 MMG5_int k,kt,nn,iel,list[MMG5_LMAX],tlist[MMG5_LMAX],*adja,iad;
824
825 /* assign seed to vertex */
826 for (k=1; k<=mesh->nt; k++) {
827 pt = &mesh->tria[k];
828 if ( !MG_EOK(pt) ) continue;
829 for (i=0; i<3; i++) {
830 ppt = &mesh->point[pt->v[i]];
831 if ( !ppt->s ) ppt->s = k;
832 }
833 }
834
835 /* allocate memory for coordinates */
836 MMG5_SAFE_CALLOC(tabl,3*mesh->np+1,double,return 0);
837
838 /* Pointer toward the suitable adjacency array */
839 adja = mesh->adja;
840
841 it = 0;
842 nit = 10;
843 res0 = 0.0;
844 lm1 = 0.4;
845 lm2 = 0.399;
846 while ( it++ < nit ) {
847 /* step 1: laplacian */
848 for (k=1; k<=mesh->np; k++) {
849 ppt = &mesh->point[k];
850
851 iad = 3*(k-1)+1;
852 tabl[iad+0] = ppt->c[0];
853 tabl[iad+1] = ppt->c[1];
854 tabl[iad+2] = ppt->c[2];
855
856 if ( !MG_VOK(ppt) ) continue;
857 if ( ppt->tag & MG_CRN || ppt->tag & MG_NOM || MG_EDG(ppt->tag) ) continue;
858
859 iel = ppt->s;
860
861 pt = &mesh->tria[iel];
862 i = 0;
863 if ( pt->v[1] == k ) i = 1;
864 else if ( pt->v[2] == k ) i = 2;
865
866 ilist = MMG5_boulep(mesh,iel,i,adja,list,tlist);
867
868 /* average coordinates */
869 cx = cy = cz = 0.0;
870 for (i=1; i<=ilist; i++) {
871 p0 = &mesh->point[list[i]];
872
873 cptr = p0->c;
874 cx += cptr[0];
875 cy += cptr[1];
876 cz += cptr[2];
877 }
878 cx /= ilist;
879 cy /= ilist;
880 cz /= ilist;
881
882 /* Laplacian */
883 cptr = ppt->c;
884 tabl[iad+0] = cptr[0] + lm1 * (cx - cptr[0]);
885 tabl[iad+1] = cptr[1] + lm1 * (cy - cptr[1]);
886 tabl[iad+2] = cptr[2] + lm1 * (cz - cptr[2]);
887 }
888
889 /* step 2: anti-laplacian */
890 res = 0;
891 nn = 0;
892 for (k=1; k<=mesh->np; k++) {
893 ppt = &mesh->point[k];
894
895 if ( !MG_VOK(ppt) ) continue;
896 if ( ppt->tag & MG_CRN || ppt->tag & MG_NOM || MG_EDG(ppt->tag) ) continue;
897
898 iel = ppt->s;
899
900 pt = &mesh->tria[iel];
901 i = 0;
902 if ( pt->v[1] == k ) i = 1;
903 else if ( pt->v[2] == k ) i = 2;
904
905 ilist = MMG5_boulep(mesh,iel,i,adja,list,tlist);
906
907 /* average normal */
908 cx = cy = cz = 0.0;
909 for (i=1; i<=ilist; i++) {
910 iad = 3*(list[i]-1) + 1;
911 cx += tabl[iad+0];
912 cy += tabl[iad+1];
913 cz += tabl[iad+2];
914 }
915 cx /= ilist;
916 cy /= ilist;
917 cz /= ilist;
918
919 /* antiLaplacian */
920 iad = 3*(k-1)+1;
921 c[0] = tabl[iad+0] - lm2 * (cx - tabl[iad+0]);
922 c[1] = tabl[iad+1] - lm2 * (cy - tabl[iad+1]);
923 c[2] = tabl[iad+2] - lm2 * (cz - tabl[iad+2]);
924
925 cptr = ppt->c;
926
927 mesh->point[0].c[0] = c[0];
928 mesh->point[0].c[1] = c[1];
929 mesh->point[0].c[2] = c[2];
930
931 /* check for negative areas */
932 noupdate = 0;
933 for (kt = 0 ; kt<ilist ; kt++) {
934 pt = &mesh->tria[tlist[kt]];
935
936 if ( !MG_EOK(pt) ) continue;
937
938 MMG5_nortri(mesh, pt, n);
939
940 for (i=0;i<3;i++) {
941 tnew.v[i] = pt->v[i];
942 }
943
944 i = 0;
945 if ( pt->v[1] == k ) i = 1;
946 if ( pt->v[2] == k ) i = 2;
947
948 tnew.v[i] = 0;
949
950 MMG5_nortri(mesh, &tnew, nnew);
951 MMG5_dotprod(3,n,nnew,&result);
952 if ( result < 0.0 ) {
953 if (!MMGS_dichotomy(mesh,&tnew,k,c,n))
954 noupdate = 1;
955 continue;
956 }
957 }
958 if ( !noupdate ) {
959 res += (cptr[0]-c[0])*(cptr[0]-c[0]) + (cptr[1]-c[1])*(cptr[1]-c[1]) + (cptr[2]-c[2])*(cptr[2]-c[2]);
960 cptr[0] = c[0];
961 cptr[1] = c[1];
962 cptr[2] = c[2];
963 nn++;
964 }
965 }
966 if ( it == 1 ) res0 = res;
967 if ( res0 > MMG5_EPSD ) res = res / res0;
968 if ( mesh->info.imprim < -1 || mesh->info.ddebug ) {
969 fprintf(stdout," iter %5d res %.3E\r",it,res);
970 fflush(stdout);
971 }
972 if ( it > 1 && res < MMG5_EPS ) break;
973 }
974 /* reset the ppt->s tag */
975 for (k=1; k<=mesh->np; ++k) {
976 mesh->point[k].s = 0;
977 }
978
979 if ( mesh->info.imprim < -1 || mesh->info.ddebug ) fprintf(stdout,"\n");
980
981 if ( abs(mesh->info.imprim) > 4 )
982 fprintf(stdout," %" MMG5_PRId " coordinates regularized: %.3e\n",nn,res);
983
984 MMG5_SAFE_FREE(tabl);
985 return 1;
986}
987
997 MMG5_Hash hash;
998 MMG5_pTria ptt;
999 MMG5_int k,jel,dup;
1000
1001 if ( !mesh->nt ) return 1;
1002
1003 /* Hash triangles */
1004 if ( ! MMG5_hashNew(mesh,&hash,(MMG5_int)(0.51*mesh->nt),(MMG5_int)(1.51*mesh->nt)) ) {
1005 return 0;
1006 }
1007
1008 dup = 0;
1009 for (k=1; k<=mesh->nt; k++) {
1010 ptt = &mesh->tria[k];
1011 jel = MMG5_hashFace(mesh,&hash,ptt->v[0],ptt->v[1],ptt->v[2],k);
1012 if ( !jel ) {
1013 MMG5_DEL_MEM(mesh,hash.item);
1014 return 0;
1015 }
1016 else if ( jel > 0 ) {
1017 ++dup;
1018 /* Remove duplicated face */
1019 MMGS_delElt(mesh,k);
1020 }
1021 }
1022
1023 if ( abs(mesh->info.imprim) > 5 && dup > 0 ) {
1024 fprintf(stdout," ## "); fflush(stdout);
1025 if ( dup > 0 ) fprintf(stdout," %"MMG5_PRId" duplicate removed",dup);
1026 fprintf(stdout,"\n");
1027 }
1028
1029 MMG5_DEL_MEM(mesh,hash.item);
1030
1031 return 1;
1032}
1033
1043
1044 /* create adjacency */
1045 if ( !MMGS_hashTria(mesh) ) {
1046 fprintf(stderr,"\n ## Hashing problem. Exit program.\n");
1047 return 0;
1048 }
1049
1050 /* delete badly shaped elts */
1051 /*if ( mesh->info.badkal && !delbad(mesh) ) {
1052 fprintf(stderr,"\n ## Geometry trouble. Exit program.\n");
1053 return 0;
1054 }*/
1055
1056 /* identify connexity */
1057 if ( !MMGS_setadj(mesh) ) {
1058 fprintf(stderr,"\n ## Topology problem. Exit program.\n");
1059 return 0;
1060 }
1061
1062 /* check for nomanifold point */
1063 nmpoints(mesh);
1064
1065 /* check for ridges */
1066 if ( mesh->info.dhd > MMG5_ANGLIM && !setdhd(mesh) ) {
1067 fprintf(stderr,"\n ## Geometry problem. Exit program.\n");
1068 return 0;
1069 }
1070
1071 /* identify singularities */
1072 if ( !MMG5_singul(mesh) ) {
1073 fprintf(stderr,"\n ## Singularity problem. Exit program.\n");
1074 return 0;
1075 }
1076
1077 /* define normals */
1078 if ( !mesh->xp ) {
1079 if ( !norver(mesh) ) {
1080 fprintf(stderr,"\n ## Normal problem. Exit program.\n");
1081 return 0;
1082 }
1083 /* regularize normals */
1084 if ( mesh->info.nreg && !MMG5_regnor(mesh) ) {
1085 fprintf(stderr,"\n ## Normal regularization problem. Exit program.\n");
1086 return 0;
1087 }
1088 }
1089 return 1;
1090}
1091
1092
1093/* preprocessing stage: mesh analysis */
1095
1096 /* Update tags stored into tria */
1097 if ( !MMGS_bdryUpdate(mesh) ) {
1098 fprintf(stderr,"\n ## Analysis problem. Exit program.\n");
1099 return 0;
1100 }
1101
1102 /* set edges tags and refs to tria */
1103 if ( !MMGS_assignEdge(mesh) ) {
1104 fprintf(stderr,"\n ## Analysis problem. Exit program.\n");
1105 return 0;
1106 }
1107
1108 /* create adjacency */
1109 if ( !MMGS_hashTria(mesh) ) {
1110 fprintf(stderr,"\n ## Hashing problem. Exit program.\n");
1111 return 0;
1112 }
1113
1114 /* delete badly shaped elts */
1115 /*if ( mesh->info.badkal && !delbad(mesh) ) {
1116 fprintf(stderr,"\n ## Geometry trouble. Exit program.\n");
1117 return 0;
1118 }*/
1119
1120 /* identify connexity */
1121 if ( !MMGS_setadj(mesh) ) {
1122 fprintf(stderr,"\n ## Topology problem. Exit program.\n");
1123 return 0;
1124 }
1125
1126 /* check for nomanifold point */
1127 nmpoints(mesh);
1128
1129 /* check for ridges */
1130 if ( mesh->info.dhd > MMG5_ANGLIM && !setdhd(mesh) ) {
1131 fprintf(stderr,"\n ## Geometry problem. Exit program.\n");
1132 return 0;
1133 }
1134
1135 /* identify singularities */
1136 if ( !MMG5_singul(mesh) ) {
1137 fprintf(stderr,"\n ## Singularity problem. Exit program.\n");
1138 return 0;
1139 }
1140
1141 /* regularize vertices coordinates */
1142 if ( mesh->info.xreg && !MMGS_regver(mesh) ){
1143 fprintf(stderr,"\n ## Coordinates regularization problem. Exit program.\n");
1144 return 0;
1145 }
1146
1147 /* define normals */
1148 if ( !mesh->xp ) {
1149 if ( !norver(mesh) ) {
1150 fprintf(stderr,"\n ## Normal problem. Exit program.\n");
1151 return 0;
1152 }
1153 /* regularize normals */
1154 if ( mesh->info.nreg && !MMG5_regnor(mesh) ) {
1155 fprintf(stderr,"\n ## Normal regularization problem. Exit program.\n");
1156 return 0;
1157 }
1158 }
1159
1160 return 1;
1161}
1162
int ier
if(!ier) exit(EXIT_FAILURE)
MMG5_pMesh * mesh
int MMG5_regnor(MMG5_pMesh mesh)
Definition: analys.c:46
int MMGS_analys_for_norver(MMG5_pMesh mesh)
Definition: analys_s.c:1042
static int setdhd(MMG5_pMesh mesh)
Definition: analys_s.c:445
static int MMGS_dichotomy(MMG5_pMesh mesh, MMG5_pTria pt, MMG5_int k, double *c, double *n)
Definition: analys_s.c:754
int MMGS_regver(MMG5_pMesh mesh)
Definition: analys_s.c:817
static int norver(MMG5_pMesh mesh)
Definition: analys_s.c:599
int MMGS_analys(MMG5_pMesh mesh)
Definition: analys_s.c:1094
static void nmpoints(MMG5_pMesh mesh)
Definition: analys_s.c:253
int MMGS_setadj(MMG5_pMesh mesh)
Definition: analys_s.c:47
int MMGS_remDup(MMG5_pMesh mesh)
Definition: analys_s.c:996
static int MMG5_singul(MMG5_pMesh mesh)
Definition: analys_s.c:496
int MMG5_boulec(MMG5_pMesh mesh, MMG5_int *adjt, MMG5_int start, int ip, double *tt)
Definition: boulep.c:199
MMG5_Info info
int MMG5_boulet(MMG5_pMesh mesh, MMG5_int start, int ip, MMG5_int *list, int8_t s, int8_t *opn)
Definition: boulep.c:363
int MMG5_boulep(MMG5_pMesh mesh, MMG5_int start, int ip, MMG5_int *adja, MMG5_int *list, MMG5_int *tlist)
Definition: boulep.c:52
int MMG5_bouler(MMG5_pMesh mesh, MMG5_int *adjt, MMG5_int start, int ip, MMG5_int *list, MMG5_int *listref, int *ng, int *nr, int lmax)
Definition: boulep.c:287
int MMG5_boulen(MMG5_pMesh mesh, MMG5_int *adjt, MMG5_int start, int ip, double *nn)
Definition: boulep.c:119
#define MMG5_EPSD
#define MMG5_EPS
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_hashNew(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int hsiz, MMG5_int hmax)
Definition: hash.c:526
int MMGS_assignEdge(MMG5_pMesh mesh)
Definition: hash_s.c:113
int MMGS_bdryUpdate(MMG5_pMesh mesh)
Definition: hash_s.c:169
int MMGS_hashTria(MMG5_pMesh mesh)
Definition: hash_s.c:77
int MMGS_delElt(MMG5_pMesh mesh, MMG5_int iel)
Definition: zaldy_s.c:93
#define MMGS_XPMAX
#define MS_SIN(tag)
#define MG_REQ
#define MG_GEO
#define MMG5_SAFE_CALLOC(ptr, size, type, law)
#define MG_EOK(pt)
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#define MMG5_GAP
#define MMG5_ADD_MEM(mesh, size, message, law)
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
#define MMG5_ANGLIM
#define MMG5_TAB_RECALLOC(mesh, ptr, initSize, wantedGap, type, message, law)
#define MMG5_TRIA_LMAX
#define MMG5_LMAX
static const uint8_t MMG5_inxt2[6]
#define MG_VOK(ppt)
void MMG5_dotprod(int8_t dim, double *a, double *b, double *result)
Definition: tools.c:265
int MMG5_nortri(MMG5_pMesh mesh, MMG5_pTria pt, double *n)
Definition: tools.c:209
#define MG_CRN
#define MMG5_SAFE_MALLOC(ptr, size, type, law)
#define MG_NOM
#define MMG5_EPSD2
#define MG_REF
#define MMG5_SAFE_FREE(ptr)
#define MMG5_DEL_MEM(mesh, ptr)
Identic as MMG5_HGeom but use MMG5_hedge to store edges instead of MMG5_hgeom (memory economy).
Definition: libmmgtypes.h:595
MMG5_hedge * item
Definition: libmmgtypes.h:597
int8_t ddebug
Definition: libmmgtypes.h:532
double dhd
Definition: libmmgtypes.h:518
int8_t xreg
Definition: libmmgtypes.h:531
int8_t nreg
Definition: libmmgtypes.h:530
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_int nc1
Definition: libmmgtypes.h:615
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_int * adja
Definition: libmmgtypes.h:624
MMG5_int npmax
Definition: libmmgtypes.h:612
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:642
MMG5_int xp
Definition: libmmgtypes.h:620
MMG5_int base
Definition: libmmgtypes.h:616
MMG5_int nt
Definition: libmmgtypes.h:612
MMG5_pTria tria
Definition: libmmgtypes.h:647
MMG5_int np
Definition: libmmgtypes.h:612
MMG5_int xpmax
Definition: libmmgtypes.h:612
Structure to store points of a MMG mesh.
Definition: libmmgtypes.h:270
double n[3]
Definition: libmmgtypes.h:272
int16_t tag
Definition: libmmgtypes.h:284
MMG5_int tmp
Definition: libmmgtypes.h:280
double c[3]
Definition: libmmgtypes.h:271
MMG5_int xp
Definition: libmmgtypes.h:279
MMG5_int s
Definition: libmmgtypes.h:283
MMG5_int flag
Definition: libmmgtypes.h:282
MMG5_int edg[3]
Definition: libmmgtypes.h:339
int16_t tag[3]
Definition: libmmgtypes.h:342
MMG5_int ref
Definition: libmmgtypes.h:335
MMG5_int flag
Definition: libmmgtypes.h:341
MMG5_int base
Definition: libmmgtypes.h:336
MMG5_int v[3]
Definition: libmmgtypes.h:334
MMG5_int cc
Definition: libmmgtypes.h:337
Structure to store surface points of a MMG mesh.
Definition: libmmgtypes.h:294
double n2[3]
Definition: libmmgtypes.h:295
double n1[3]
Definition: libmmgtypes.h:295