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