Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
analys_2d.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*/
35#include "libmmg2d_private.h"
36
37extern int8_t ddb;
38
50int MMG2D_setadj(MMG5_pMesh mesh, int8_t init_cc) {
51 MMG5_pTria pt,pt1;
52 MMG5_pQuad pq;
53 MMG5_int *pile,*adja,ipil,k,kk,ncc,ip1,ip2,nr,nref;
54 uint16_t tag;
55 int8_t i,ii,i1,i2;
56
57 if ( !mesh->nt ) {
58 return 1;
59 }
60
61 if ( abs(mesh->info.imprim) > 5 || mesh->info.ddebug )
62 fprintf(stdout," ** SETTING TOPOLOGY\n");
63
65 MMG5_SAFE_MALLOC(pile,mesh->nt+1,MMG5_int,return 0);
66
67 /* Reinitialization of cc field (as we pass in steadj more than once) */
68 if ( init_cc ) {
69 for ( k=1; k<=mesh->nt; ++k ) {
70 mesh->tria[k].cc = 0;
71 }
72 }
73
74 /* Initialization of the pile */
75 ncc = 1;
76 pile[1] = 1;
77 ipil = 1;
78 mesh->tria[1].cc = ncc;
79 nr = nref =0;
80
81 while ( ipil > 0 ) {
82
83 while ( ipil > 0 ) {
84 k = pile[ipil];
85 ipil--;
86
87 pt = &mesh->tria[k];
88 if ( !MG_EOK(pt) ) continue;
89 adja = &mesh->adja[3*(k-1)+1];
90
91 for (i=0; i<3; i++) {
92 i1 = MMG5_inxt2[i];
93 i2 = MMG5_iprv2[i];
94 ip1 = pt->v[i1];
95 ip2 = pt->v[i2];
96
97 if ( adja[i] ) {
98 kk = adja[i] / 3;
99 ii = adja[i] % 3;
100 pt1 = &mesh->tria[kk];
101
102 if ( (!mesh->info.opnbdy) && (pt->ref==pt1->ref) ) {
103 /* Remove BDY/REF and GEO edge tags but required tag must be kept
104 * (to preserve required tria info) */
105 pt->tag[i] &= ~MG_REF;
106 pt->tag[i] &= ~MG_BDY;
107 pt->tag[i] &= ~MG_GEO;
108
109 pt1->tag[ii] &= ~MG_REF;
110 pt1->tag[ii] &= ~MG_BDY;
111 pt1->tag[ii] &= ~MG_GEO;
112
113 pt1->tag[ii] |= pt->tag[i];
114 pt->tag[i] |= pt1->tag[ii];
115 }
116 else {
117 /* Transfert edge tag to adjacent */
118 pt1->tag[ii] |= pt->tag[i];
119 pt->tag[i] |= pt1->tag[ii];
120 }
121 }
122
123 /* Transfer tags if i is already an edge (e.g. supplied by the user) */
124 if ( MG_EDG(pt->tag[i]) || (pt->tag[i] & MG_REQ) ) {
125 mesh->point[ip1].tag |= pt->tag[i];
126 mesh->point[ip2].tag |= pt->tag[i];
127 }
128
129 /* Case of an external boundary */
130 if ( !adja[i] ) {
131 tag = ( MG_GEO+MG_BDY );
132
133 if ( ( !(pt->tag[i] & MG_REQ) ) &&
134 ( mesh->info.nosurf || (pt->tag[i] & MG_PARBDY ) ) ) {
135 pt->tag[i] |= ( tag + MG_REQ + MG_NOSURF );
136 }
137 else
138 pt->tag[i] |= tag;
139
140 if ( ( !(mesh->point[ip1].tag & MG_REQ) ) &&
141 ( mesh->info.nosurf || (pt->tag[i] & MG_PARBDY ) ) ) {
142 mesh->point[ip1].tag |= ( tag+MG_REQ+MG_NOSURF );
143 }
144 else {
145 mesh->point[ip1].tag |= tag;
146 }
147
148 if ( ( !(mesh->point[ip2].tag & MG_REQ) ) &&
149 ( mesh->info.nosurf || (pt->tag[i] & MG_PARBDY ) ) ) {
150 mesh->point[ip2].tag |= ( tag+MG_REQ+MG_NOSURF );
151 }
152 else {
153 mesh->point[ip2].tag |= tag;
154 }
155 nr++;
156 continue;
157 }
158 kk = adja[i] / 3;
159 ii = adja[i] % 3;
160 pt1 = &mesh->tria[kk];
161
162 /* Case of a boundary (except if opnbdy is enabled, the boundary must be
163 * between 2 different subdomains) */
164 if ( (mesh->info.opnbdy && ( pt->tag[i] || pt1->tag[ii] ) )
165 || MMG5_abs(pt1->ref) != MMG5_abs(pt->ref) ) {
166 tag = ( MG_REF+MG_BDY );
167
168 if ( !mesh->info.nosurf ) {
169 pt->tag[i] |= tag;
170 pt1->tag[ii] |= tag;
171 mesh->point[ip1].tag |= tag;
172 mesh->point[ip2].tag |= tag;
173 }
174 else {
175 if ( !(pt->tag[i] & MG_REQ) )
176 pt->tag[i] |= ( tag+MG_REQ+MG_NOSURF );
177 else
178 pt->tag[i] |= tag;
179
180 if ( !(pt1->tag[ii] & MG_REQ) )
181 pt1->tag[ii] |= ( tag+MG_REQ+MG_NOSURF );
182 else
183 pt1->tag[ii] |= tag;
184
185 if ( !(mesh->point[ip1].tag & MG_REQ ) )
186 mesh->point[ip1].tag |= ( tag+MG_REQ+MG_NOSURF );
187 else
188 mesh->point[ip1].tag |= tag;
189
190 if ( !(mesh->point[ip2].tag & MG_REQ ) )
191 mesh->point[ip2].tag |= ( tag+MG_REQ+MG_NOSURF );
192 else
193 mesh->point[ip2].tag |= tag;
194 }
195 if ( kk > k ) nref++;
196 continue;
197 }
198
199 if ( pt1->cc > 0 ) continue;
200 ipil++;
201 pile[ipil] = kk;
202 pt1->cc = ncc;
203 }
204 }
205
206 /* Find the starting triangle for the next connected component */
207 ipil = 0;
208 for (kk=1; kk<=mesh->nt; kk++) {
209 pt = &mesh->tria[kk];
210 if ( pt->v[0] && (pt->cc == 0) ) {
211 ipil = 1;
212 pile[ipil] = kk;
213 ncc++;
214 pt->cc = ncc;
215 break;
216 }
217 }
218 }
219 MMG5_SAFE_FREE(pile);
220
223 for ( k=1; k<=mesh->nquad; k++ ) {
224 pq = &mesh->quadra[k];
225 if ( !MG_EOK(pq) ) continue;
226
227 adja = &mesh->adjq[4*(k-1)+1];
228 for (i=0; i<4; i++) {
229
230 kk = adja[i];
231 if ( kk >= 0 ) {
232 continue;
233 }
234
235 /* The edge is at the interface between a quad and a triangle */
236 kk = MMG5_abs(kk);
237 ii = kk%3;
238 pt = &mesh->tria[kk/3];
239
240 if ( !(pt->tag[ii] & MG_REQ) ) {
241 pt->tag[ii] |= (MG_REQ + MG_NOSURF + MG_BDY);
242 }
243 if ( !(pq->tag[i] & MG_REQ) ) {
244 pq->tag[i] |= (MG_REQ + MG_NOSURF + MG_BDY);
245 }
246 assert ( pt->edg[ii] == pq->edg[i] );
247
248 /* Transfer edge tag toward edge vertices */
249 i1 = MMG2D_idir_q[i][0];
250 i2 = MMG2D_idir_q[i][1];
251
252 if ( !(mesh->point[pq->v[i1]].tag & MG_REQ) ) {
253 mesh->point[pq->v[i1]].tag |= (MG_REQ + MG_NOSURF + MG_BDY);
254 }
255 if ( !(mesh->point[pq->v[i2]].tag & MG_REQ) ) {
256 mesh->point[pq->v[i2]].tag |= (MG_REQ + MG_NOSURF + MG_BDY);
257 }
258 }
259 }
260
261
262 if ( abs(mesh->info.imprim) > 4 ) {
263 fprintf(stdout," Connected component or subdomains: %" MMG5_PRId " \n",ncc);
264 fprintf(stdout," Tagged edges: %" MMG5_PRId ", ridges: %" MMG5_PRId ", refs: %" MMG5_PRId "\n",nr+nref,nr,nref);
265 }
266
267 return 1;
268}
269
280int MMG2D_singul(MMG5_pMesh mesh, MMG5_int ref ) {
281 MMG5_pTria pt;
282 MMG5_pPoint ppt,p1,p2;
283 double ux,uy,uz,vx,vy,vz,dd;
284 MMG5_int list[MMG5_TRIA_LMAX+2],listref[MMG5_TRIA_LMAX+2],k,nm,nre,nc;
285 int ns,ng,nr;
286 int8_t i;
287
288 nre = nc = nm = 0;
289
290 if ( ref == MMG5_UNSET ) {
291 /* reset the ppt->s tag */
292 for (k=1; k<=mesh->np; ++k) {
293 mesh->point[k].s = 0;
294 }
295 }
296 else {
298 /* First: mark all the points */
299 for ( k=1; k<=mesh->np; ++k ) {
300 mesh->point[k].s = 1;
301 }
302 /* Second: if the point belongs to a boundary edge of reference ref, remove
303 * the mark */
304 for ( k=1; k<=mesh->nt; ++k ) {
305 pt = &mesh->tria[k];
306
307 for (i=0; i<3; i++) {
308 if ( !MG_EDG(pt->tag[i]) ) continue;
309 if ( pt->edg[i] != ref ) continue;
310
311 mesh->point[pt->v[MMG5_iprv2[i]]].s = 0;
312 mesh->point[pt->v[MMG5_inxt2[i]]].s = 0;
313 }
314 }
315 }
316
318 for (k=1; k<=mesh->nt; k++) {
319 pt = &mesh->tria[k];
320 if ( ! MG_EOK(pt) ) continue;
321
322 for (i=0; i<3; i++) {
323 ppt = &mesh->point[pt->v[i]];
324
325 if ( ppt->s ) continue;
326 ppt->s = 1;
327
328 if ( !MG_VOK(ppt) || MG_CRN & ppt->tag ) continue;
329
330 if ( !MG_EDG(ppt->tag) ) continue;
331
332 ns = MMG5_bouler(mesh,mesh->adja,k,i,list,listref,&ng,&nr,MMG5_TRIA_LMAX);
333
334 if ( !ns ) continue;
335 if ( (ng+nr) > 2 ) {
336 /* Previous classification may be subject to discussion, and may depend on the user's need */
337 ppt->tag |= MG_NOM;
338 nm++;
339 /* Two ridge curves and one ref curve: non manifold situation */
340 /*if ( ng == 2 && nr == 1 ) {
341 ppt->tag |= MG_NOM;
342 nm++;
343 }
344 else {
345 ppt->tag |= MG_CRN + MG_REQ;
346 nre++;
347 nc++;
348 }*/
349 }
350 /* One ridge curve and one ref curve meeting at a point */
351 else if ( (ng == 1) && (nr == 1) ) {
352 ppt->tag |= MG_REQ;
353 nre++;
354 }
355 /* Evanescent ridge */
356 else if ( ng == 1 && !nr ){
357 ppt->tag |= MG_CRN + MG_REQ;
358 nre++;
359 nc++;
360 }
361 /* Evanescent ref curve */
362 else if ( nr == 1 && !ng ){
363 ppt->tag |= MG_CRN + MG_REQ;
364 nre++;
365 nc++;
366 }
367 /* Check ridge angle */
368 else {
369 assert ( ng == 2 || nr == 2 );
370 p1 = &mesh->point[list[1]];
371 p2 = &mesh->point[list[2]];
372 ux = p1->c[0] - ppt->c[0];
373 uy = p1->c[1] - ppt->c[1];
374 uz = p1->c[2] - ppt->c[2];
375 vx = p2->c[0] - ppt->c[0];
376 vy = p2->c[1] - ppt->c[1];
377 vz = p2->c[2] - ppt->c[2];
378 dd = (ux*ux + uy*uy + uz*uz) * (vx*vx + vy*vy + vz*vz);
379
380 /* If both edges carry different refs, tag vertex as singular */
381 if ( listref[1] != listref[2] ) {
382 ppt->tag |= MG_REQ;
383 nc++;
384 }
385
386 /* Check angle */
387 if ( fabs(dd) > MMG5_EPSD ) {
388 dd = (ux*vx + uy*vy + uz*vz) / sqrt(dd);
389 if ( dd > -mesh->info.dhd ) {
390 ppt->tag |= MG_CRN;
391 nc++;
392 }
393 }
394 }
395 }
396 }
397
398 if ( abs(mesh->info.imprim) > 3 && nc+nre+nm > 0 )
399 fprintf(stdout," %" MMG5_PRId " corners, %" MMG5_PRId " singular points and %" MMG5_PRId " non manifold points detected\n",nc,nre,nm);
400
401 return 1;
402}
403
414int MMG2D_norver(MMG5_pMesh mesh, MMG5_int ref) {
415 MMG5_pTria pt,pt1;
416 MMG5_pPoint ppt;
417 MMG5_int k,kk,nn,pleft,pright;
418 int8_t i,ii;
419
420 nn = 0;
421
422 if ( ref == MMG5_UNSET ) {
423 /* reset the ppt->s tag */
424 for (k=1; k<=mesh->np; ++k) {
425 mesh->point[k].s = 0;
426 }
427 }
428 else {
430 /* First: mark all the points */
431 for ( k=1; k<=mesh->np; ++k ) {
432 mesh->point[k].s = 1;
433 }
434 /* Second: if the point belongs to a boundary edge or reference ref, remove
435 * the mark */
436 for ( k=1; k<=mesh->nt; ++k ) {
437 pt = &mesh->tria[k];
438
439 for (i=0; i<3; i++) {
440 if ( !MG_EDG(pt->tag[i]) ) continue;
441 if ( pt->edg[i] != ref ) continue;
442
443 mesh->point[pt->v[MMG5_iprv2[i]]].s = 0;
444 mesh->point[pt->v[MMG5_inxt2[i]]].s = 0;
445 }
446 }
447 }
448
449 /* Normal computation */
450 for (k=1; k<=mesh->nt; k++) {
451 pt = &mesh->tria[k];
452 if ( !MG_EOK(pt) ) continue;
453
454 for (i=0; i<3; i++) {
455 ppt = &mesh->point[pt->v[i]];
456 if ( !MG_EDG(ppt->tag) ) continue;
457 if ( ppt->s || (MG_CRN & ppt->tag) || (ppt->tag & MG_NOM) ) continue;
458
459 /* Travel the curve ppt belongs to from left to right until a singularity is met */
460 kk = k;
461 ii = i;
462 do {
463 ppt->s = 1;
464 if ( !MMG2D_boulen(mesh,kk,ii,&pleft,&pright,ppt->n) ) {
465 fprintf(stderr,"\n ## Error: %s: Impossible to"
466 " calculate normal vector at vertex %" MMG5_PRId ".\n",
467 __func__,MMG2D_indPt(mesh,pt->v[i]));
468 return 0;
469 }
470 nn++;
471
472 kk = pright / 3;
473 ii = pright % 3;
474 ii = MMG5_iprv2[ii];
475 pt1 = &mesh->tria[kk];
476 ppt = &mesh->point[pt1->v[ii]];
477 }
478 while ( !ppt->s && !(MG_CRN & ppt->tag) && !(ppt->tag & MG_NOM) );
479
480 /* Now travel the curve ppt belongs to from right to left until a singularity is met */
481 ppt = &mesh->point[pt->v[i]];
482 kk = k;
483 ii = i;
484 do {
485 ppt->s = 1;
486 if ( !MMG2D_boulen(mesh,kk,ii,&pleft,&pright,ppt->n) ) {
487 fprintf(stderr,"\n ## Error: %s: Impossible to"
488 " calculate normal vector at vertex %" MMG5_PRId ".\n",
489 __func__,MMG2D_indPt(mesh,pt->v[i]));
490 return 0;
491 }
492 nn++;
493
494 kk = pleft / 3;
495 ii = pleft % 3;
496 ii = MMG5_inxt2[ii];
497 pt1 = &mesh->tria[kk];
498 ppt = &mesh->point[pt1->v[ii]];
499 }
500 while ( !ppt->s && !(MG_CRN & ppt->tag) && !(ppt->tag & MG_NOM) );
501 }
502 }
503
504 if ( abs(mesh->info.imprim) > 3 && nn > 0 )
505 fprintf(stdout," %" MMG5_PRId " calculated normal vectors\n",nn);
506
507 return 1;
508}
509
520 MMG5_pTria pt;
521 MMG5_pPoint ppt,p1,p2;
522 double *tmp,dd,ps,lm1,lm2,nx,ny,ux,uy,nxt,nyt,res,res0,n[2];
523 MMG5_int k,iel,ip1,ip2,nn,list[MMG5_LMAX];
524 int it,maxit,ilist;
525 int8_t i,ier;
526
527 it = 0;
528 maxit = 10;
529 res0 = 0.0;
530 nn = 0;
531 lm1 = mesh->info.lxreg;
532 lm2 = 0.99*lm1;
533
534 /* Temporary table for normal vectors */
535 MMG5_SAFE_CALLOC(tmp,2*mesh->np+1,double,return 0);
536
537 /* Allocate a seed to each point */
538 for (k=1; k<=mesh->nt; k++) {
539 pt = &mesh->tria[k];
540 if ( !MG_EOK(pt) ) continue;
541
542 for (i=0; i<3; i++) {
543 ppt = &mesh->point[pt->v[i]];
544 ppt->s = k;
545 }
546 }
547
548 do {
549 /* Step 1: Laplacian */
550 for (k=1; k<=mesh->np; k++) {
551 ppt = &mesh->point[k];
552 if ( !MG_VOK(ppt) ) continue;
553 if ( MG_SIN(ppt->tag) || ppt->tag & MG_NOM ) continue;
554 if ( !MG_EDG(ppt->tag) ) continue;
555
556 nx = ny = 0;
557 iel = ppt->s;
558 pt = &mesh->tria[iel];
559 i = 0;
560 if ( pt->v[1] == k ) i = 1;
561 if ( pt->v[2] == k ) i = 2;
562
563 ilist = MMG2D_bouleendp(mesh,iel,i,&ip1,&ip2,list);
564
565 if ( !ilist ) {
566 fprintf(stderr,"\n ## Error: %s: Abort.\n",__func__);
568 return 0;
569 }
570
571 p1 = &mesh->point[ip1];
572 p2 = &mesh->point[ip2];
573
574 /* If p1 is singular, update with the (adequately oriented) normal to the edge ppt-p1 */
575 if ( MG_SIN(p1->tag) || p1->tag & MG_NOM ) {
576 ux = p1->c[0] - ppt->c[0];
577 uy = p1->c[1] - ppt->c[1];
578 dd = ux*ux + uy*uy;
579 if ( dd > MMG5_EPSD ) {
580 dd = 1.0 / sqrt(dd);
581 ux *= dd;
582 uy *= dd;
583 }
584 nxt = -uy;
585 nyt = ux;
586
587 ps = nxt*ppt->n[0] + nyt*ppt->n[1];
588 if ( ps < 0.0 ) {
589 nx += -nxt;
590 ny += -nyt;
591 }
592 else {
593 nx += nxt;
594 ny += nyt;
595 }
596 }
597 else {
598 nx += p1->n[0];
599 ny += p1->n[1];
600 }
601
602 /* If p2 is singular, update with the (adequately oriented) normal to the edge ppt-p1 */
603 if ( MG_SIN(p2->tag) || p2->tag & MG_NOM ) {
604 ux = p2->c[0] - ppt->c[0];
605 uy = p2->c[1] - ppt->c[1];
606 dd = ux*ux + uy*uy;
607 if ( dd > MMG5_EPSD ) {
608 dd = 1.0 / sqrt(dd);
609 ux *= dd;
610 uy *= dd;
611 }
612 nxt = -uy;
613 nyt = ux;
614
615 ps = nxt*ppt->n[0] + nyt*ppt->n[1];
616 if ( ps < 0.0 ) {
617 nx += -nxt;
618 ny += -nyt;
619 }
620 else {
621 nx += nxt;
622 ny += nyt;
623 }
624 }
625 else {
626 nx += p2->n[0];
627 ny += p2->n[1];
628 }
629
630 /* Average normal normalization */
631 dd = nx*nx + ny*ny;
632 if ( dd > MMG5_EPSD2 ) {
633 dd = 1.0 / sqrt(dd);
634 nx *= dd;
635 ny *= dd;
636 }
637
638 /* Laplacian operation */
639 tmp[2*(k-1)+1] = ppt->n[0] + lm1 * (nx - ppt->n[0]);
640 tmp[2*(k-1)+2] = ppt->n[1] + lm1 * (ny - ppt->n[1]);
641 }
642
643 /* Antilaplacian operation */
644 res = 0.0;
645 for (k=1; k<=mesh->np; k++) {
646
647 ppt = &mesh->point[k];
648 if ( !MG_VOK(ppt) ) continue;
649 if ( MG_SIN(ppt->tag) || ppt->tag & MG_NOM ) continue;
650 if ( !MG_EDG(ppt->tag) ) continue;
651
652 nx = ny = 0;
653 iel = ppt->s;
654 pt = &mesh->tria[iel];
655 i = 0;
656 if ( pt->v[1] == k ) i = 1;
657 if ( pt->v[2] == k ) i = 2;
658
659 ilist = MMG2D_bouleendp(mesh,iel,i,&ip1,&ip2,list);
660 if ( !ilist ) {
661 fprintf(stderr,"\n ## Error: %s: Abort.\n",__func__);
663 return 0;
664 }
665
666 p1 = &mesh->point[ip1];
667 p2 = &mesh->point[ip2];
668
669 /* If p1 is singular, update with the (adequately oriented) normal to the edge ppt-p1 */
670 if ( MG_SIN(p1->tag) || p1->tag & MG_NOM ) {
671 ux = p1->c[0] - ppt->c[0];
672 uy = p1->c[1] - ppt->c[1];
673 dd = ux*ux + uy*uy;
674 if ( dd > MMG5_EPSD ) {
675 dd = 1.0 / sqrt(dd);
676 ux *= dd;
677 uy *= dd;
678 }
679 nxt = -uy;
680 nyt = ux;
681
682 ps = nxt*ppt->n[0] + nyt*ppt->n[1];
683 if ( ps < 0.0 ) {
684 nx += -nxt;
685 ny += -nyt;
686 }
687 else {
688 nx += nxt;
689 ny += nyt;
690 }
691 }
692 else {
693 nx += tmp[2*(ip1-1)+1];
694 ny += tmp[2*(ip1-1)+2];
695 }
696
697 /* If p2 is singular, update with the (adequately oriented) normal to the edge ppt-p1 */
698 if ( MG_SIN(p2->tag) || p2->tag & MG_NOM ) {
699 ux = p2->c[0] - ppt->c[0];
700 uy = p2->c[1] - ppt->c[1];
701 dd = ux*ux + uy*uy;
702 if ( dd > MMG5_EPSD ) {
703 dd = 1.0 / sqrt(dd);
704 ux *= dd;
705 uy *= dd;
706 }
707 nxt = -uy;
708 nyt = ux;
709
710 ps = nxt*ppt->n[0] + nyt*ppt->n[1];
711 if ( ps < 0.0 ) {
712 nx += -nxt;
713 ny += -nyt;
714 }
715 else {
716 nx += nxt;
717 ny += nyt;
718 }
719 }
720 else {
721 nx += tmp[2*(ip2-1)+1];
722 ny += tmp[2*(ip2-1)+2];
723 }
724
725 /* Average normal normalization */
726 dd = nx*nx + ny*ny;
727 if ( dd > MMG5_EPSD2 ) {
728 dd = 1.0 / sqrt(dd);
729 nx *= dd;
730 ny *= dd;
731 }
732
733 /* Anti Laplacian operation */
734 n[0] = tmp[2*(k-1)+1] - lm2 * (nx - tmp[2*(k-1)+1]);
735 n[1] = tmp[2*(k-1)+2] - lm2 * (ny - tmp[2*(k-1)+2]);
736 res += (n[0]-ppt->n[0])*(n[0]-ppt->n[0]) + (n[1]-ppt->n[1])*(n[1]-ppt->n[1]);
737 ppt->n[0] = n[0];
738 ppt->n[1] = n[1];
739 nn++;
740 }
741
742 /* Normalization */
743 for (k=1; k<=mesh->np; k++) {
744 ppt = &mesh->point[k];
745 if ( !MG_VOK(ppt) ) continue;
746 if ( MG_SIN(ppt->tag) || ppt->tag & MG_NOM ) continue;
747 if ( !MG_EDG(ppt->tag) ) continue;
748
749 dd = ppt->n[0]*ppt->n[0] + ppt->n[1]*ppt->n[1];
750 if ( dd > MMG5_EPSD ) {
751 dd = 1.0 / sqrt(dd);
752 ppt->n[0] *= dd;
753 ppt->n[1] *= dd;
754 }
755 }
756
757 if ( it == 0 ) res0 = res;
758 if ( res0 > MMG5_EPSD ) res = res / res0;
759
760 if ( mesh->info.imprim < -1 || mesh->info.ddebug ) {
761 fprintf(stdout," iter %5d res %.3E",it,res);
762 fflush(stdout);
763 }
764 }
765 while ( ++it < maxit && res > MMG5_EPS );
766
767
768 if ( abs(mesh->info.imprim) > 4 )
769 fprintf(stdout," %" MMG5_PRId " normals regularized: %.3e\n",nn,res);
770
772 return 1;
773}
774
787static inline int MMG2D_dichotomy(MMG5_pMesh mesh, MMG5_pTria pt, MMG5_int k, double *c) {
788
789 MMG5_pPoint ppt;
790 double p[2],co[3][2],vol,to,tp,t;
791 int it,maxit,pos,i,j;
792
793 it = 0;
794 maxit = 5;
795 to = 0.0;
796 tp = 1.0;
797 t = 0.5;
798 pos = 0;
799
800 ppt = &mesh->point[k];
801
802 for ( i=0 ; i<3 ; i++ ) {
803 for ( j=0 ; j<2 ; j++ ) {
804 co[i][j] = mesh->point[pt->v[i]].c[j];
805 }
806 }
807
808 /* initial coordinates of new point */
809 p[0] = c[0];
810 p[1] = c[1];
811
812 i = 0;
813 if ( pt->v[1] == k ) i = 1;
814 if ( pt->v[2] == k ) i = 2;
815
816 do {
817 co[i][0] = ppt->c[0] + t*(p[0] - ppt->c[0]);
818 co[i][1] = ppt->c[1] + t*(p[1] - ppt->c[1]);
819
820 vol = MMG2D_quickarea(co[0],co[1],co[2]);
821
822 if ( vol <= 0.0 ) {
823 tp = t;
824 }
825 else {
826 c[0] = co[i][0];
827 c[1] = co[i][1];
828 to = t;
829 pos = 1;
830 }
831
832 t = 0.5*(to + tp);
833 }
834 while ( ++it < maxit );
835
836 if ( pos ) {
837 return 1;
838 }
839 else
840 return 0;
841}
842
843
854 MMG5_pTria pt;
855 MMG5_pPoint ppt,p1,p2;
856 double *tmp,lm1,lm2,cx,cy,res,res0,c[2],co[3][2],vol;
857 MMG5_int k,kt,iel,ip1,ip2,nn,list[MMG5_LMAX];
858 int it,maxit,j,ilist,noupdate;
859 int8_t i;
860
861 it = 0;
862 maxit=10;
863 res0 = 0.0;
864 nn = 0;
865 lm1 = 0.4;
866 lm2 = 0.399;
867
868 /* Temporary table for coordinates */
869 MMG5_SAFE_CALLOC(tmp,2*mesh->np+1,double,return 0);
870
871 /* Allocate a seed to each point */
872 for (k=1; k<=mesh->nt; k++) {
873 pt = &mesh->tria[k];
874 if ( !MG_EOK(pt) ) continue;
875
876 for (i=0; i<3; i++) {
877 ppt = &mesh->point[pt->v[i]];
878 ppt->s = k;
879 }
880 }
881
882 do {
883 /* Step 1: Laplacian */
884 for (k=1; k<=mesh->np; k++) {
885 ppt = &mesh->point[k];
886 tmp[2*(k-1)+1] = ppt->c[0];
887 tmp[2*(k-1)+2] = ppt->c[1];
888
889 if ( !MG_VOK(ppt) ) continue;
890 if ( MG_SIN(ppt->tag) || ppt->tag & MG_NOM ) continue;
891 if ( !MG_EDG(ppt->tag) ) continue;
892
893 cx = cy = 0;
894 iel = ppt->s;
895 pt = &mesh->tria[iel];
896 i = 0;
897 if ( pt->v[1] == k ) i = 1;
898 if ( pt->v[2] == k ) i = 2;
899
900 ilist = MMG2D_bouleendp(mesh,iel,i,&ip1,&ip2,list);
901
902 if ( !ilist ) {
903 fprintf(stderr,"\n ## Error: %s: Abort.\n",__func__);
905 return 0;
906 }
907
908 p1 = &mesh->point[ip1];
909 p2 = &mesh->point[ip2];
910
911 cx += p1->c[0];
912 cy += p1->c[1];
913
914 cx += p2->c[0];
915 cy += p2->c[1];
916 cx *= 0.5;
917 cy *= 0.5;
918
919 /* Laplacian operation */
920 tmp[2*(k-1)+1] = ppt->c[0] + lm1 * (cx - ppt->c[0]);
921 tmp[2*(k-1)+2] = ppt->c[1] + lm1 * (cy - ppt->c[1]);
922 }
923
924 /* Antilaplacian operation */
925 res = 0.0;
926 for (k=1; k<=mesh->np; k++) {
927
928 ppt = &mesh->point[k];
929 if ( !MG_VOK(ppt) ) continue;
930 if ( MG_SIN(ppt->tag) || ppt->tag & MG_NOM ) continue;
931 if ( !MG_EDG(ppt->tag) ) continue;
932
933 cx = cy = 0;
934 iel = ppt->s;
935 pt = &mesh->tria[iel];
936 i = 0;
937 if ( pt->v[1] == k ) i = 1;
938 if ( pt->v[2] == k ) i = 2;
939
940 ilist = MMG2D_bouleendp(mesh,iel,i,&ip1,&ip2,list);
941
942 if ( !ilist ) {
943 fprintf(stderr,"\n ## Error: %s: Abort.\n",__func__);
945 return 0;
946 }
947
948 cx += tmp[2*(ip1-1)+1];
949 cy += tmp[2*(ip1-1)+2];
950
951 cx += tmp[2*(ip2-1)+1];
952 cy += tmp[2*(ip2-1)+2];
953 cx *= 0.5;
954 cy *= 0.5;
955
956 /* Anti Laplacian operation */
957 c[0] = tmp[2*(k-1)+1] - lm2 * (cx - tmp[2*(k-1)+1]);
958 c[1] = tmp[2*(k-1)+2] - lm2 * (cy - tmp[2*(k-1)+2]);
959
960 /* Check if updated point creates a triangle with negative area.
961 If it does, performs a dichotomy to find optimal point */
962 noupdate = 0;
963 for (kt=0; kt<ilist;kt++) {
964 pt = &mesh->tria[list[kt]];
965 if ( !MG_EOK(pt) ) continue;
966
967 for ( i=0 ; i<3 ; i++ ) {
968 for ( j=0 ; j<2 ; j++ ) {
969 co[i][j] = mesh->point[pt->v[i]].c[j];
970 }
971 }
972
973 i = 0;
974 if ( pt->v[1] == k ) i = 1;
975 if ( pt->v[2] == k ) i = 2;
976
977 for ( j=0 ; j<2 ; j++ ) {
978 co[i][j] = c[j];
979 }
980
981 vol = MMG2D_quickarea(co[0],co[1],co[2]);
982
983 if ( vol <= 0.0 ) {
984 if (!MMG2D_dichotomy(mesh,pt,k,c)) noupdate = 1;
985 continue;
986 }
987 }
988 if ( !noupdate ) {
989 res += (c[0]-ppt->c[0])*(c[0]-ppt->c[0]) + (c[1]-ppt->c[1])*(c[1]-ppt->c[1]);
990 ppt->c[0] = c[0];
991 ppt->c[1] = c[1];
992 nn++;
993 }
994 }
995
996 if ( it == 0 ) res0 = res;
997 if ( res0 > MMG5_EPSD ) res = res / res0;
998
999 if ( mesh->info.imprim < -1 || mesh->info.ddebug ) {
1000 fprintf(stdout," iter %5d res %.3E",it,res);
1001 fflush(stdout);
1002 }
1003 }
1004 while ( ++it < maxit && res > MMG5_EPS );
1005
1006 if ( abs(mesh->info.imprim) > 4 )
1007 fprintf(stdout," %" MMG5_PRId " coordinates regularized: %.3e\n",nn,res);
1008
1010 return 1;
1011}
1012
1015
1016 /* Transfer the boundary edge references to the triangles, if it has not been
1017 * already done (option 1) */
1018 if ( !MMG2D_assignEdge(mesh) ) {
1019 fprintf(stderr,"\n ## Problem in setting boundary. Exit program.\n");
1020 return 0;
1021 }
1022
1023 /* Creation of tria adjacency relations in the mesh */
1024 if ( !MMG2D_hashTria(mesh) ) {
1025 fprintf(stderr,"\n ## Hashing problem. Exit program.\n");
1026 return 0;
1027 }
1028
1029 /* Creation quadrilaterals adjacency relations in the mesh */
1030 if ( !MMG2D_hashQuad(mesh) ) {
1031 fprintf(stderr,"\n ## Quadrilaterals hashing problem. Exit program.\n");
1032 return 0;
1033 }
1034
1035 /* Set tags to triangles from geometric configuration */
1036 int8_t init_cc = 0;
1037 if ( mesh->info.isosurf ) {
1038 init_cc = 1;
1039 }
1040
1045 if ( !MMG2D_setadj(mesh,init_cc) ) {
1046 fprintf(stderr,"\n ## Problem in function setadj. Exit program.\n");
1047 return 0;
1048 }
1049
1050 /* Identify singularities in the mesh */
1051 if ( !MMG2D_singul(mesh,MMG5_UNSET) ) {
1052 fprintf(stderr,"\n ## Problem in identifying singularities. Exit program.\n");
1053 return 0;
1054 }
1055
1056 /* Regularize vertix vector field with a Laplacian / anti-laplacian smoothing */
1057 if ( mesh->info.xreg && !MMG2D_regver(mesh) ) {
1058 fprintf(stderr,"\n ## Problem in regularizing vertices coordinates. Exit program.\n");
1059 return 0;
1060 }
1061
1062 /* Define normal vectors at vertices on curves */
1063 if ( !MMG2D_norver(mesh,MMG5_UNSET) ) {
1064 fprintf(stderr,"\n ## Problem in calculating normal vectors. Exit program.\n");
1065 return 0;
1066 }
1067
1068 /* Regularize normal vector field with a Laplacian / anti-laplacian smoothing */
1069 if ( mesh->info.nreg && !MMG2D_regnor(mesh) ) {
1070 fprintf(stderr,"\n ## Problem in regularizing normal vectors. Exit program.\n");
1071 return 0;
1072 }
1073
1074 if ( mesh->nquad ) MMG5_DEL_MEM(mesh,mesh->adjq);
1075
1076 return 1;
1077}
int ier
tmp[*strlen0]
MMG5_pMesh * mesh
int MMG2D_singul(MMG5_pMesh mesh, MMG5_int ref)
Definition: analys_2d.c:280
int MMG2D_regver(MMG5_pMesh mesh)
Definition: analys_2d.c:853
int MMG2D_regnor(MMG5_pMesh mesh)
Definition: analys_2d.c:519
int MMG2D_analys(MMG5_pMesh mesh)
Definition: analys_2d.c:1014
int8_t ddb
Definition: mmg3d1_delone.c:42
int MMG2D_setadj(MMG5_pMesh mesh, int8_t init_cc)
Definition: analys_2d.c:50
static int MMG2D_dichotomy(MMG5_pMesh mesh, MMG5_pTria pt, MMG5_int k, double *c)
Definition: analys_2d.c:787
int MMG2D_norver(MMG5_pMesh mesh, MMG5_int ref)
Definition: analys_2d.c:414
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 MMG2D_bouleendp(MMG5_pMesh mesh, MMG5_int start, int8_t ip, MMG5_int *ip1, MMG5_int *ip2, MMG5_int *list)
Definition: boulep_2d.c:231
int MMG2D_boulen(MMG5_pMesh mesh, MMG5_int start, int8_t ip, MMG5_int *pleft, MMG5_int *pright, double *nn)
Definition: boulep_2d.c:115
#define MMG5_EPSD
#define MMG5_EPS
int MMG2D_hashQuad(MMG5_pMesh mesh)
Definition: hash_2d.c:151
int MMG2D_assignEdge(MMG5_pMesh mesh)
Definition: hash_2d.c:334
int MMG2D_hashTria(MMG5_pMesh mesh)
Definition: hash_2d.c:35
MMG5_int MMG2D_indPt(MMG5_pMesh mesh, MMG5_int kp)
Definition: tools_2d.c:70
static const uint8_t MMG2D_idir_q[4][2]
idir[i]: vertices of edge i for a quad
#define MG_REQ
#define MG_GEO
#define MMG5_SAFE_CALLOC(ptr, size, type, law)
double MMG2D_quickarea(double a[2], double b[2], double c[2])
Definition: tools.c:971
#define MG_EOK(pt)
#define MG_PARBDY
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
#define MG_SIN(tag)
#define MMG5_TRIA_LMAX
#define MMG5_LMAX
#define MMG5_UNSET
static const uint8_t MMG5_inxt2[6]
#define MG_VOK(ppt)
#define MG_CRN
#define MG_BDY
#define MMG5_SAFE_MALLOC(ptr, size, type, law)
#define MG_NOSURF
#define MG_NOM
#define MMG5_EPSD2
#define MG_REF
#define MMG5_SAFE_FREE(ptr)
#define MMG5_DEL_MEM(mesh, ptr)
int8_t ddebug
Definition: libmmgtypes.h:539
int8_t isosurf
Definition: libmmgtypes.h:542
double lxreg
Definition: libmmgtypes.h:526
uint8_t nosurf
Definition: libmmgtypes.h:553
double dhd
Definition: libmmgtypes.h:525
int8_t xreg
Definition: libmmgtypes.h:538
int8_t nreg
Definition: libmmgtypes.h:537
MMG mesh structure.
Definition: libmmgtypes.h:613
MMG5_pQuad quadra
Definition: libmmgtypes.h:656
MMG5_Info info
Definition: libmmgtypes.h:659
MMG5_pPoint point
Definition: libmmgtypes.h:649
MMG5_int * adja
Definition: libmmgtypes.h:632
MMG5_int nquad
Definition: libmmgtypes.h:621
MMG5_int * adjq
Definition: libmmgtypes.h:644
MMG5_int nt
Definition: libmmgtypes.h:620
MMG5_pTria tria
Definition: libmmgtypes.h:655
MMG5_int np
Definition: libmmgtypes.h:620
Structure to store vertices of an MMG mesh.
Definition: libmmgtypes.h:276
double n[3]
Definition: libmmgtypes.h:278
double c[3]
Definition: libmmgtypes.h:277
uint16_t tag
Definition: libmmgtypes.h:290
MMG5_int s
Definition: libmmgtypes.h:289
Structure to store quadrangles of an MMG mesh.
Definition: libmmgtypes.h:372
MMG5_int v[4]
Definition: libmmgtypes.h:373
uint16_t tag[4]
Definition: libmmgtypes.h:378
MMG5_int edg[4]
Definition: libmmgtypes.h:376
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