Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
mmg2d1.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*/
33#include "libmmg2d_private.h"
35
36/* Mesh adaptation routine for the first stages of the algorithm: intertwine splitting
37 based on patterns, collapses and swaps.
38 typchk = 1 -> adaptation based on edge lengths
39 typchk = 2 -> adaptation based on lengths calculated in metric met */
40int MMG2D_anatri(MMG5_pMesh mesh,MMG5_pSol met,int8_t typchk) {
41 int it,maxit;
42 MMG5_int ns,nc,nsw,nns,nnc,nnsw;
43
44 nns = nnc = nnsw = 0;
45 it = 0;
46 maxit = 5;
47
48 /* Main routine; intertwine split, collapse and swaps */
49 do {
50 if ( typchk == 2 && it == 0 ) {
51// #warning Luca: check consistency with 3D
52 }
53 if ( !mesh->info.noinsert ) {
54 /* Memory free */
56 mesh->adja = 0;
57
58 /* Split long edges according to patterns */
59 ns = MMG2D_anaelt(mesh,met,typchk);
60 if ( ns < 0 ) {
61 fprintf(stderr," ## Unable to complete surface mesh. Exit program.\n");
62 return 0;
63 }
64
65 /* Recreate adjacencies */
66 if ( !MMG2D_hashTria(mesh) ) {
67 fprintf(stdout," ## Hashing problem. Exit program.\n");
68 return 0;
69 }
70
71 /* Collapse short edges */
72 nc = MMG2D_colelt(mesh,met,typchk);
73 if ( nc < 0 ) {
74 fprintf(stderr," ## Unable to collapse mesh. Exiting.\n");
75 return 0;
76 }
77
78 }
79 else {
80 ns = 0;
81 nc = 0;
82 }
83 /* Swap edges */
84 if ( !mesh->info.noswap ) {
85 nsw = MMG2D_swpmsh(mesh,met,typchk);
86 if ( nsw < 0 ) {
87 fprintf(stderr," ## Unable to improve mesh. Exiting.\n");
88 return 0;
89 }
90 }
91 else nsw = 0;
92
93 nns += ns;
94 nnc += nc;
95 nnsw += nsw;
96
97 if ( (abs(mesh->info.imprim) > 4 || mesh->info.ddebug) && ns+nc > 0 )
98 fprintf(stdout," %8" MMG5_PRId " splitted, %8" MMG5_PRId " collapsed, %8" MMG5_PRId " swapped\n",ns,nc,nsw);
99 if ( it > 3 && MMG5_abs(nc-ns) < 0.1 * MG_MAX(nc,ns) ) break;
100 }
101 while ( ++it < maxit && ns+nc+nsw >0 );
102
103 if ( mesh->info.imprim > 0 ) {
104 if ( (abs(mesh->info.imprim) < 5 || mesh->info.ddebug ) && nns+nnc > 0 )
105 fprintf(stdout," %8" MMG5_PRId " splitted, %8" MMG5_PRId " collapsed, %8" MMG5_PRId " swapped, %d iter.\n",nns,nnc,nnsw,it);
106 }
107 return 1;
108}
109
110/* Travel triangles and split long edges according to patterns */
111MMG5_int MMG2D_anaelt(MMG5_pMesh mesh,MMG5_pSol met,int typchk) {
112 MMG5_pTria pt;
113 MMG5_pPoint ppt,p1,p2;
114 MMG5_Hash hash;
115 double len,s,o[2],no[2];
116 int it;
117 MMG5_int ni,npinit,ns,nc,k,nt,ip1,ip2,ip,vx[3];
118 int8_t i,ic,i1,i2,ier;
119 static int8_t mmgWarn0=0;
120
121 s = 0.5;
122 ns = 0;
123 npinit = mesh->np;
124
125 if ( !MMG5_hashNew(mesh,&hash,mesh->np,3*mesh->np) ) return 0;
126
127 /* Step 1: travel mesh, check edges, and tag those to be split; create the new vertices in hash */
128 for (k=1; k<=mesh->nt; k++) {
129 pt = &mesh->tria[k];
130 if ( !MG_EOK(pt) || (pt->ref < 0) ) continue;
131 if ( MG_SIN(pt->tag[0]) || MG_SIN(pt->tag[1]) || MG_SIN(pt->tag[2]) ) continue;
132
133 /* Check if pt should be cut */
134 pt->flag = 0;
135
136 /* typchk=1 : split on geometric basis and rough size considerations */
137 if ( typchk == 1) {
138 if ( !MMG2D_chkedg(mesh,k) ) continue;
139 }
140 /* typchk =2 : split on basis of edge lengths in the metric */
141 else if ( typchk ==2 ) {
142 for (i=0; i<3; i++) {
143 i1 = MMG5_inxt2[i];
144 i2 = MMG5_iprv2[i];
145 len = MMG2D_lencurv(mesh,met,pt->v[i1],pt->v[i2]);
146 if ( len > MMG2D_LLONG ) MG_SET(pt->flag,i);
147 }
148 }
149
150 /* mesh->info.fem : split edges which are not MG_BDY, but whose vertices are both MG_BDY */
151 if ( mesh->info.fem ) {
152 for (i=0; i<3; i++) {
153 i1 = MMG5_inxt2[i];
154 i2 = MMG5_iprv2[i];
155 p1 = &mesh->point[pt->v[i1]];
156 p2 = &mesh->point[pt->v[i2]];
157 if ( (p1->tag & MG_BDY) && (p2->tag & MG_BDY) && !(pt->tag[i] & MG_BDY) ) MG_SET(pt->flag,i);
158 }
159 }
160
161 if ( !pt->flag ) continue;
162 ns++;
163
164 /* Travel edges to split and create new points */
165 for (i=0; i<3; i++) {
166 if ( !MG_GET(pt->flag,i) ) continue;
167 i1 = MMG5_inxt2[i];
168 i2 = MMG5_iprv2[i];
169 ip1 = pt->v[i1];
170 ip2 = pt->v[i2];
171 ip = MMG5_hashGet(&hash,ip1,ip2);
172 if ( ip > 0 ) continue;
173
174 /* Geometric attributes of the new point */
175 ier = MMG2D_bezierCurv(mesh,k,i,s,o,no);
176 if ( !ier ) {
177 MG_CLR(pt->flag,i);
178 continue;
179 }
180 ip = MMG2D_newPt(mesh,o,pt->tag[i]);
181 if ( !ip ) {
182 /* reallocation of point table */
184 fprintf(stderr,"\n ## Error: %s: unable to"
185 " allocate a new point.\n",__func__);
187 do {
189 } while ( mesh->np>npinit );return -1;,
190 o,pt->tag[i]);
191 }
192 ppt = &mesh->point[ip];
193 if ( MG_EDG(pt->tag[i]) ) {
194 ppt->n[0] = no[0];
195 ppt->n[1] = no[1];
196 }
197
198 /* If there is a metric in the mesh, interpolate it at the new point */
199 assert ( met );
200 if ( met->m )
201 MMG2D_intmet(mesh,met,k,i,ip,s);
202
203 /* Add point to the hashing structure */
204 MMG5_hashEdge(mesh,&hash,ip1,ip2,ip);
205 }
206 }
207 if ( !ns ) {
208 MMG5_DEL_MEM(mesh,hash.item);
209 return ns;
210 }
211
212 /* Step 2: Make flags at triangles consistent between themselves (check if adjacent triangle is split) */
213 for (k=1; k<=mesh->nt; k++) {
214 pt = &mesh->tria[k];
215 if ( !MG_EOK(pt) || pt->ref < 0 ) continue;
216 else if ( pt->flag == 7 ) continue;
217 nc = 0;
218
219 for (i=0; i<3; i++) {
220 i1 = MMG5_iprv2[i];
221 i2 = MMG5_inxt2[i];
222 if ( !MG_GET(pt->flag,i) && !MG_SIN(pt->tag[i]) ) {
223 ip = MMG5_hashGet(&hash,pt->v[i1],pt->v[i2]);
224 if ( ip > 0 ) {
225 MG_SET(pt->flag,i);
226 nc++;
227 }
228 }
229 }
230 if ( nc > 0 ) ns++;
231 }
232 if ( mesh->info.ddebug && ns ) {
233 fprintf(stdout," %" MMG5_PRId " analyzed %" MMG5_PRId " proposed\n",mesh->nt,ns);
234 fflush(stdout);
235 }
236 /* Step 3: Simulate splitting and delete points leading to an invalid configuration */
237 for (k=1; k<=mesh->np; k++)
238 mesh->point[k].flag = 0;
239
240 it = 1;
241 nc = 0;
242 do {
243 ni = 0;
244 for ( k=1; k<= mesh->nt; k++) {
245 pt = &mesh->tria[k];
246 if ( !MG_EOK(pt) || pt->ref < 0 ) continue;
247 else if ( pt->flag == 0 ) continue;
248
249 vx[0] = vx[1] =vx[2] = 0;
250 pt->flag = 0;
251 ic = 0;
252
253 for (i=0; i<3; i++) {
254 i1 = MMG5_iprv2[i];
255 i2 = MMG5_inxt2[i];
256 vx[i] = MMG5_hashGet(&hash,pt->v[i1],pt->v[i2]);
257 if ( vx[i] > 0 ) {
258 MG_SET(pt->flag,i);
259 if ( mesh->point[vx[i]].flag > 2 ) ic = 1;
260 }
261 }
262
263 if ( !pt->flag ) continue;
264 switch (pt->flag) {
265 case 1: case 2: case 4:
266 ier = MMG2D_split1_sim(mesh,met,k,vx);
267 break;
268 case 7:
269 ier = MMG2D_split3_sim(mesh,met,k,vx);
270 break;
271 default:
272 ier = MMG2D_split2_sim(mesh,met,k,vx);
273 break;
274 }
275 if ( ier ) continue;
276
277 /* An edge is invalidated in the process */
278 ni++;
279 if ( ic == 0 && MMG2D_dichoto(mesh,met,k,vx) ) {
280 for (i=0; i<3; i++)
281 if ( vx[i] > 0 ) mesh->point[vx[i]].flag++;
282 }
283 /* Relocate point at the center of the edge */
284 else {
285 for (i=0; i<3; i++) {
286 if ( vx[i] > 0 ) {
287 p1 = &mesh->point[pt->v[MMG5_iprv2[i]]];
288 p2 = &mesh->point[pt->v[MMG5_inxt2[i]]];
289 ppt = &mesh->point[vx[i]];
290 ppt->c[0] = 0.5 * (p1->c[0] + p2->c[0]);
291 ppt->c[1] = 0.5 * (p1->c[1] + p2->c[1]);
292 }
293 }
294 }
295 }
296 nc += ni;
297 }
298 while ( ni >0 && ++it <20 );
299
300 if ( mesh->info.ddebug && nc ) {
301 fprintf(stdout," %" MMG5_PRId " corrected, %" MMG5_PRId " invalid\n",nc,ni);
302 fflush(stdout);
303 }
304
305 /* step 4: effective splitting */
306 ns = 0;
307 nt = mesh->nt;
308 for (k=1; k<=nt; k++) {
309 pt = &mesh->tria[k];
310 if ( !MG_EOK(pt) || pt->ref < 0 ) continue;
311 else if ( pt->flag == 0 ) continue;
312
313 vx[0] = vx[1] = vx[2] = 0;
314 for (i=0; i<3; i++) {
315 i1 = MMG5_inxt2[i];
316 i2 = MMG5_inxt2[i1];
317 if ( MG_GET(pt->flag,i) ) {
318 vx[i] = MMG5_hashGet(&hash,pt->v[i1],pt->v[i2]);
319 if ( !vx[i] ) {
320 if ( !mmgWarn0 ) {
321 mmgWarn0 = 1;
322 fprintf(stderr,"\n ## Error: %s: unable to create point on"
323 " at least 1 edge.\n Exit program.\n",__func__);
324 }
325 return -1;
326 }
327 }
328 }
329 if ( pt->flag == 1 || pt->flag == 2 || pt->flag == 4 ) {
330 ier = MMG2D_split1(mesh,met,k,vx);
331 ns++;
332 }
333 else if ( pt->flag == 7 ) {
334 ier = MMG2D_split3(mesh,met,k,vx);
335 ns++;
336 }
337 else {
338 ier = MMG2D_split2(mesh,met,k,vx);
339 ns++;
340 }
341 if ( !ier ) return -1;
342 }
343 if ( (mesh->info.ddebug || abs(mesh->info.imprim) > 5) && ns > 0 )
344 fprintf(stdout," %7" MMG5_PRId " splitted\n",ns);
345 MMG5_DEL_MEM(mesh,hash.item);
346
347 return ns;
348}
349
360int MMG2D_dichoto(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int k,MMG5_int *vx) {
361 MMG5_pTria pt;
362 MMG5_pPoint pa,pb,ps;
363 double o[3][2],p[3][2];
364 float to,tp,t;
365 MMG5_int ia,ib;
366 int ier,it,maxit;
367 int8_t i,i1,i2;
368
369 pt = &mesh->tria[k];
370
371 /* Get point on curve and along segment for edge split */
372 for (i=0; i<3; i++) {
373 memset(p[i],0,2*sizeof(double));
374 memset(o[i],0,2*sizeof(double));
375 if ( vx[i] > 0 ) {
376 i1 = MMG5_inxt2[i];
377 i2 = MMG5_inxt2[i1];
378 ia = pt->v[i1];
379 ib = pt->v[i2];
380 pa = &mesh->point[ia];
381 pb = &mesh->point[ib];
382 ps = &mesh->point[vx[i]];
383 o[i][0] = 0.5 * (pa->c[0] + pb->c[0]);
384 o[i][1] = 0.5 * (pa->c[1] + pb->c[1]);
385 p[i][0] = ps->c[0];
386 p[i][1] = ps->c[1];
387 }
388 }
389 maxit = 4;
390 it = 0;
391 tp = 1.0;
392 to = 0.0;
393
394 do {
395 /* compute new position */
396 t = 0.5 * (tp + to);
397 for (i=0; i<3; i++) {
398 if ( vx[i] > 0 ) {
399 ps = &mesh->point[vx[i]];
400 ps->c[0] = o[i][0] + t*(p[i][0] - o[i][0]);
401 ps->c[1] = o[i][1] + t*(p[i][1] - o[i][1]);
402 }
403 }
404 switch (pt->flag) {
405 case 1: case 2: case 4:
406 ier = MMG2D_split1_sim(mesh,met,k,vx);
407 break;
408 case 7:
409 ier = MMG2D_split3_sim(mesh,met,k,vx);
410 break;
411 default:
412 ier = MMG2D_split2_sim(mesh,met,k,vx);
413 break;
414 }
415 if ( ier )
416 to = t;
417 else
418 tp = t;
419 }
420 while ( ++it < maxit );
421
422 /* restore coords of last valid pos. */
423 if ( !ier ) {
424 t = to;
425 for (i=0; i<3; i++) {
426 if ( vx[i] > 0 ) {
427 ps = &mesh->point[vx[i]];
428 ps->c[0] = o[i][0] + t*(p[i][0] - o[i][0]);
429 ps->c[1] = o[i][1] + t*(p[i][1] - o[i][1]);
430 }
431 }
432 }
433 return 1;
434}
435
436/* Travel triangles and collapse short edges */
437MMG5_int MMG2D_colelt(MMG5_pMesh mesh,MMG5_pSol met,int typchk) {
438 MMG5_pTria pt;
439 MMG5_pPoint p1,p2;
440 double ux,uy,ll,hmin2;
441 MMG5_int k;
442 int ilist;
443 MMG5_int nc;
444 uint8_t i,i1,i2,open;
445 MMG5_int list[MMG5_TRIA_LMAX+2];
446
447 nc = 0;
448 hmin2 = mesh->info.hmin * mesh->info.hmin;
449
450 for (k=1; k<=mesh->nt; k++) {
451 pt = &mesh->tria[k];
452 if ( !MG_EOK(pt) || pt->ref < 0 ) continue;
453
454 /* Travel 3 edges of the triangle and decide whether to collapse p1->p2, based on length criterion */
455 pt->flag = 0; // was here before, but probably serves for nothing
456
457 for (i=0; i<3; i++) {
458 if ( MG_SIN(pt->tag[i]) ) continue;
459 i1 = MMG5_inxt2[i];
460 i2 = MMG5_iprv2[i];
461 p1 = &mesh->point[pt->v[i1]];
462 p2 = &mesh->point[pt->v[i2]];
463 if ( MG_SIN(p1->tag) || p1->tag & MG_NOM ) continue;
464
465 /* Impossible to collapse a surface point onto a non surface point -- impossible to
466 collapse a surface point along a non geometric edge */
467 else if ( p1->tag & MG_GEO ) {
468 if ( ! (p2->tag & MG_GEO) || !(pt->tag[i] & MG_GEO) ) continue;
469 }
470 /* Same test for REF points */
471 else if ( p1->tag & MG_REF ) {
472 if ( ! (p2->tag & MG_GEO || p2->tag & MG_REF) || !(pt->tag[i] & MG_REF) ) continue;
473 }
474
475 open = (mesh->adja[3*(k-1)+1+i] == 0) ? 1 : 0;
476
477 /* Check length */
478 if ( typchk == 1 ) {
479 ux = p2->c[0] - p1->c[0];
480 uy = p2->c[1] - p1->c[1];
481 ll = ux*ux + uy*uy;
482 if ( ll > hmin2 ) continue;
483 }
484 else {
485 ll = MMG2D_lencurv(mesh,met,pt->v[i1],pt->v[i2]);
486 if ( ll > MMG2D_LSHRT ) continue;
487 }
488
489 /* Check whether the geometry is preserved */
490 ilist = MMG2D_chkcol(mesh,met,k,i,list,typchk);
491
492 if ( ilist > 3 || ( ilist == 3 && open ) ) {
493 nc += MMG2D_colver(mesh,ilist,list);
494 break;
495 }
496 else if ( ilist == 3 ) {
497 nc += MMG2D_colver3(mesh,list);
498 break;
499 }
500 else if ( ilist == 2 ) {
501 nc += MMG2D_colver2(mesh,list);
502 break;
503 }
504 }
505 }
506
507 if ( nc > 0 && (abs(mesh->info.imprim) > 5 || mesh->info.ddebug) )
508 fprintf(stdout," %8" MMG5_PRId " vertices removed\n",nc);
509
510 return nc;
511}
512
513/* Travel triangles and swap edges to improve quality */
514MMG5_int MMG2D_swpmsh(MMG5_pMesh mesh,MMG5_pSol met,int typchk) {
515 MMG5_pTria pt;
516 int it,maxit;
517 MMG5_int ns,nns;
518 MMG5_int k;
519 uint8_t i;
520
521 it = nns = 0;
522 maxit = 2;
523 mesh->base++;
524
525 do {
526 ns = 0;
527 for (k=1; k<=mesh->nt; k++) {
528 pt = &mesh->tria[k];
529 if ( !MG_EOK(pt) || pt->ref < 0 ) continue;
530
531 for (i=0; i<3; i++) {
532 if ( MG_SIN(pt->tag[i]) || MG_EDG(pt->tag[i]) ) continue;
533 else if ( MMG2D_chkswp(mesh,met,k,i,typchk) ) {
534 ns += MMG2D_swapar(mesh,k,i);
535 break;
536 }
537 }
538 }
539 nns += ns;
540 }
541 while ( ns > 0 && ++it<maxit );
542 if ( (abs(mesh->info.imprim) > 5 || mesh->info.ddebug) && nns > 0 )
543 fprintf(stdout," %8" MMG5_PRId " edge swapped\n",nns);
544 return nns;
545}
546
547
548/* Mesh adaptation routine for the final stage of the algorithm: intertwine splitting
549 based on patterns, collapses, swaps and vertex relocations.*/
551 int maxit,it;
552 MMG5_int nns,ns,nnc,nc,nnsw,nsw,nnm,nm;
553
554 nns = nnc = nnsw = nnm = it = 0;
555 maxit = 5;
556
557 do {
558
559 if ( !mesh->info.noinsert ) {
560 ns = MMG2D_adpspl(mesh,met);
561 if ( ns < 0 ) {
562 fprintf(stderr," ## Problem in function adpspl."
563 " Unable to complete mesh. Exit program.\n");
564 return 0;
565 }
566
567 nc = MMG2D_adpcol(mesh,met);
568 if ( nc < 0 ) {
569 fprintf(stderr," ## Problem in function adpcol."
570 " Unable to complete mesh. Exit program.\n");
571 return 0;
572 }
573 }
574 else {
575 ns = 0;
576 nc = 0;
577 }
578
579 if ( !mesh->info.noswap ) {
580 nsw = MMG2D_swpmsh(mesh,met,2);
581 if ( nsw < 0 ) {
582 fprintf(stderr," ## Problem in function swpmsh."
583 " Unable to complete mesh. Exit program.\n");
584 return 0;
585 }
586 }
587 else
588 nsw = 0;
589
590 if ( !mesh->info.nomove ) {
591 nm = MMG2D_movtri(mesh,met,1,0);
592 if ( nm < 0 ) {
593 fprintf(stderr," ## Problem in function movtri. "
594 "Unable to complete mesh. Exit program.\n");
595 return 0;
596 }
597 }
598 else
599 nm = 0;
600
601 nns += ns;
602 nnc += nc;
603 nnsw += nsw;
604 nnm += nm;
605
606 if ( (abs(mesh->info.imprim) > 4 || mesh->info.ddebug) && ns+nc+nsw+nm > 0 )
607 fprintf(stdout," %8" MMG5_PRId " splitted, %8" MMG5_PRId " collapsed, %8" MMG5_PRId " swapped, %8" MMG5_PRId " moved\n",ns,nc,nsw,nm);
608 if ( ns < 10 && MMG5_abs(nc-ns) < 3 ) break;
609 else if ( it > 3 && MMG5_abs(nc-ns) < 0.3 * MG_MAX(nc,ns) ) break;
610 }
611 while( ++it < maxit && (nc+ns+nsw+nm > 0) );
612
613 /* Last iterations of vertex relocation only */
614 if ( !mesh->info.nomove ) {
615 nm = MMG2D_movtri(mesh,met,5,1);
616 if ( nm < 0 ) {
617 fprintf(stderr," ## Problem in function movtri. Unable to complete mesh."
618 " Exit program.\n");
619 return 0;
620 }
621 nnm += nm;
622 }
623 if ( mesh->info.imprim > 0 ) {
624 if ( abs(mesh->info.imprim) < 5 && (nnc > 0 || nns > 0) )
625 fprintf(stdout," %8" MMG5_PRId " splitted, %8" MMG5_PRId " collapsed, %8" MMG5_PRId " swapped, %8" MMG5_PRId " moved, %d iter. \n",nns,nnc,nnsw,nnm,it);
626 }
627 return 1;
628}
629
641 MMG5_pTria pt;
642 double lmax,len;
643 MMG5_int ip,ns,k,nt;
644 int ier;
645 int8_t i,i1,i2,imax;
646
647 ns = 0;
648
649 /*loop until nt to avoid the split of new triangle*/
650 nt = mesh->nt;
651 for (k=1; k<=nt; k++) {
652 pt = &mesh->tria[k];
653 if ( !MG_EOK(pt) || pt->ref < 0 ) continue;
654
655 imax = -1;
656 lmax = -1.0;
657 for (i=0; i<3; i++) {
658 if ( MG_SIN(pt->tag[i]) ) continue;
659 i1 = MMG5_inxt2[i];
660 i2 = MMG5_iprv2[i];
661
662 len = MMG2D_lencurv(mesh,met,pt->v[i1],pt->v[i2]);
663
664 if ( len > lmax ) {
665 lmax = len;
666 imax = i;
667 }
668 }
669
670 if ( lmax < MMG2D_LOPTL ) continue;
671 else if ( MG_SIN(pt->tag[imax]) ) continue;
672
673 /* Check the feasibility of splitting */
674 ip = MMG2D_chkspl(mesh,met,k,imax);
675
676 /* Lack of memory; abort the routine */
677 if ( ip < 0 ){
678 return ns;
679 }
680 else if ( ip > 0 ) {
681 ier = MMG2D_split1b(mesh,k,imax,ip);
682
683 /* Lack of memory; abort the routine */
684 if ( !ier ) {
685 MMG2D_delPt(mesh,ip);
686 return ns;
687 }
688 ns += ier;
689 }
690 }
691
692 return ns;
693}
694
695/* Analysis and collapse routine for edges in the final step of the algorithm */
697 MMG5_pTria pt;
698 MMG5_pPoint p1,p2;
699 double len;
700 MMG5_int k,nc;
701 int ilist;
702 int8_t i,i1,i2,open;
703 MMG5_int list[MMG5_TRIA_LMAX+2];
704
705 nc = 0;
706 for (k=1; k<=mesh->nt; k++) {
707 pt = &mesh->tria[k];
708 if ( !MG_EOK(pt) || pt->ref < 0 ) continue;
709
710 /* Check edge length, and attempt collapse */
711 pt->flag = 0;
712 for (i=0; i<3; i++) {
713 if ( MG_SIN(pt->tag[i]) ) continue;
714
715 open = ( mesh->adja[3*(k-1)+1+i] == 0 ) ? 1 : 0;
716
717 i1 = MMG5_inxt2[i];
718 i2 = MMG5_iprv2[i];
719 p1 = &mesh->point[pt->v[i1]];
720 p2 = &mesh->point[pt->v[i2]];
721
722 if ( MG_SIN(p1->tag) || p1->tag & MG_NOM ) continue;
723 else if ( p1->tag & MG_GEO ) {
724 if ( ! (p2->tag & MG_GEO) || !(pt->tag[i] & MG_GEO) ) continue;
725 }
726 else if ( p1->tag & MG_REF ) {
727 if ( ! (p2->tag & MG_GEO || p2->tag & MG_REF) || !(pt->tag[i] & MG_REF) ) continue;
728 }
729
730 len = MMG2D_lencurv(mesh,met,pt->v[i1],pt->v[i2]);
731
732 if ( len > MMG2D_LOPTS ) continue;
733
734 ilist = MMG2D_chkcol(mesh,met,k,i,list,2);
735
736 if ( ilist > 3 || ( ilist==3 && open ) ) {
737 nc += MMG2D_colver(mesh,ilist,list);
738 break;
739 }
740 else if ( ilist == 3 ) {
741 nc += MMG2D_colver3(mesh,list);
742 break;
743 }
744 else if ( ilist == 2 ) {
745 nc += MMG2D_colver2(mesh,list);
746 break;
747 }
748 }
749 }
750
751 return nc;
752}
753
754/* Analyze points to relocate them according to a quality criterion */
755MMG5_int MMG2D_movtri(MMG5_pMesh mesh,MMG5_pSol met,int maxit,int8_t improve) {
756 MMG5_pTria pt;
757 MMG5_pPoint p0;
758 MMG5_int nnm,nm,ns,k;
759 int it,ilist;
760 int8_t i,ier;
761 MMG5_int base,list[MMG5_TRIA_LMAX+2];
762
763 it = nnm = 0;
764 base = 0;
765
766 for (k=1; k<=mesh->np; k++)
767 mesh->point[k].flag = base;
768
769 do {
770 base++;
771 nm = ns = 0;
772 for (k=1; k<=mesh->nt; k++) {
773 pt = &mesh->tria[k];
774 if ( !MG_EOK(pt) || pt->ref < 0 ) continue;
775
776 for (i=0; i<3; i++) {
777 p0 = &mesh->point[pt->v[i]];
778 if ( p0->flag == base || MG_SIN(p0->tag) || p0->tag & MG_NOM ) continue;
779
780 int8_t dummy;
781 ilist = MMG5_boulet(mesh,k,i,list,0,&dummy);
782
783 if ( MG_EDG(p0->tag) ) {
784 ier = MMG2D_movedgpt(mesh,met,ilist,list,improve);
785 if ( ier ) ns++;
786 }
787 else {
788 if ( met->size == 3 && met->m )
789 ier = MMG2D_movintpt_ani(mesh,met,ilist,list,improve);
790 else
791 ier = MMG2D_movintpt(mesh,met,ilist,list,improve);
792 }
793
794 if ( ier ) {
795 nm++;
796 p0->flag = base;
797 }
798 }
799 }
800 nnm += nm;
801 if ( mesh->info.ddebug ) fprintf(stdout," %8" MMG5_PRId " moved, %" MMG5_PRId " geometry\n",nm,ns);
802 }
803 while ( ++it < maxit && nm > 0 );
804
805 if ( (abs(mesh->info.imprim) > 5 || mesh->info.ddebug) && nnm > 0 )
806 fprintf(stdout," %8" MMG5_PRId " vertices moved, %d iter.\n",nnm,it);
807
808 return nnm;
809}
810
820
821 /* Stage 1: creation of a geometric mesh */
822 if ( abs(mesh->info.imprim) > 4 || mesh->info.ddebug )
823 fprintf(stdout," ** GEOMETRIC MESH\n");
824
825 if ( !MMG2D_anatri(mesh,met,1) ) {
826 fprintf(stderr," ## Unable to split mesh-> Exiting.\n");
827 return 0;
828 }
829
830 /* Debug: export variable MMG_SAVE_ANATRI1 to save adapted mesh at the end of
831 * anatri wave */
832 if ( getenv("MMG_SAVE_ANATRI1") ) {
833 printf(" ## WARNING: EXIT AFTER ANATRI-1."
834 " (MMG_SAVE_ANATRI1 env variable is exported).\n");
835 return 1;
836 }
837
838 /* Stage 2: creation of a computational mesh */
839 if ( abs(mesh->info.imprim) > 4 || mesh->info.ddebug ){
840 fprintf(stdout," ** COMPUTATIONAL MESH\n");
841}
842 if ( !MMG2D_defsiz(mesh,met) ) {
843 fprintf(stderr," ## Metric undefined. Exit program.\n");
844 return 0;
845 }
846
847 /* Debug: export variable MMG_SAVE_DEFSIZ to save adapted mesh at the end of
848 * anatet wave */
849 if ( getenv("MMG_SAVE_DEFSIZ") ) {
850 printf(" ## WARNING: EXIT AFTER DEFSIZ."
851 " (MMG_SAVE_DEFSIZ env variable is exported).\n");
852 return 1;
853 }
854
856 if ( mesh->info.hgrad > 0. ) {
857 if (!MMG2D_gradsiz(mesh,met) ) {
858 fprintf(stderr," ## Gradation problem. Exit program.\n");
859 return 0;
860 }
861 }
862
863 if ( mesh->info.hgradreq > 0. ) {
864 MMG2D_gradsizreq(mesh,met);
865 }
866 /* Debug: export variable MMG_SAVE_GRADSIZ to save adapted mesh at the end of
867 * anatet wave */
868 if ( getenv("MMG_SAVE_GRADSIZ") ) {
869 printf(" ## WARNING: EXIT AFTER GRADSIZ."
870 " (MMG_SAVE_GRADSIZ env variable is exported).\n");
871 return 1;
872 }
873
874 if ( !MMG2D_anatri(mesh,met,2) ) {
875 fprintf(stderr," ## Unable to proceed adaptation. Exit program.\n");
876 return 0;
877 }
878 /* Debug: export variable MMG_SAVE_ANATRI1 to save adapted mesh at the end of
879 * anatri wave */
880 if ( getenv("MMG_SAVE_ANATRI1") ) {
881 printf(" ## WARNING: EXIT AFTER ANATRI-2."
882 " (MMG_SAVE_ANATRI2 env variable is exported).\n");
883 return 1;
884 }
885
886
887 /* Stage 3: fine mesh improvements */
888 if ( !MMG2D_adptri(mesh,met) ) {
889 fprintf(stderr," ## Unable to make fine improvements. Exit program.\n");
890 return 0;
891 }
892
893 return 1;
894}
int ier
MMG5_pMesh * mesh
int MMG2D_movintpt_ani(MMG5_pMesh mesh, MMG5_pSol met, int ilist, MMG5_int *list, int8_t improve)
Definition: anisomovpt_2d.c:38
int MMG2D_bezierCurv(MMG5_pMesh mesh, MMG5_int k, int8_t i, double s, double *o, double *no)
Definition: bezier_2d.c:185
int MMG2D_chkedg(MMG5_pMesh mesh, MMG5_int k)
Definition: bezier_2d.c:28
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 MMG2D_colver(MMG5_pMesh mesh, int ilist, MMG5_int *list)
Definition: colver_2d.c:273
int MMG2D_chkcol(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int8_t i, MMG5_int *list, int8_t typchk)
Definition: colver_2d.c:42
int MMG2D_colver3(MMG5_pMesh mesh, MMG5_int *list)
Definition: colver_2d.c:359
int MMG2D_colver2(MMG5_pMesh mesh, MMG5_int *list)
Definition: colver_2d.c:421
int MMG5_hashNew(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int hsiz, MMG5_int hmax)
Definition: hash.c:526
MMG5_int MMG5_hashGet(MMG5_Hash *hash, MMG5_int a, MMG5_int b)
Definition: hash.c:495
int MMG5_hashEdge(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int a, MMG5_int b, MMG5_int k)
Definition: hash.c:345
int MMG2D_hashTria(MMG5_pMesh mesh)
Definition: hash_2d.c:35
void MMG5_gradation_info(MMG5_pMesh mesh)
Definition: isosiz.c:96
#define MMG2D_POINT_REALLOC(mesh, sol, ip, wantedGap, law, o, tag)
int MMG2D_movintpt(MMG5_pMesh, MMG5_pSol, int, MMG5_int *, int8_t)
Definition: movpt_2d.c:213
int MMG2D_split3(MMG5_pMesh, MMG5_pSol, MMG5_int, MMG5_int vx[3])
Definition: split_2d.c:630
int MMG2D_split2_sim(MMG5_pMesh, MMG5_pSol, MMG5_int, MMG5_int vx[3])
Definition: split_2d.c:456
#define MMG2D_LOPTL
int MMG2D_split2(MMG5_pMesh, MMG5_pSol, MMG5_int, MMG5_int vx[3])
Definition: split_2d.c:505
int MMG2D_chkswp(MMG5_pMesh, MMG5_pSol, MMG5_int, int8_t, int8_t)
Definition: swapar_2d.c:128
MMG5_int MMG2D_chkspl(MMG5_pMesh, MMG5_pSol, MMG5_int, int8_t)
Definition: split_2d.c:51
int MMG2D_split1b(MMG5_pMesh, MMG5_int, int8_t, MMG5_int)
Definition: split_2d.c:244
int MMG2D_split1(MMG5_pMesh, MMG5_pSol, MMG5_int, MMG5_int vx[3])
Definition: split_2d.c:390
#define MMG2D_LLONG
void MMG2D_delPt(MMG5_pMesh mesh, MMG5_int ip)
Definition: zaldy_2d.c:57
int MMG2D_split1_sim(MMG5_pMesh, MMG5_pSol, MMG5_int, MMG5_int vx[3])
Definition: split_2d.c:345
MMG5_int MMG2D_newPt(MMG5_pMesh mesh, double c[2], int16_t tag)
Definition: zaldy_2d.c:38
int MMG2D_swapar(MMG5_pMesh, MMG5_int, int8_t)
Definition: swapar_2d.c:221
#define MMG2D_LOPTS
int MMG2D_movedgpt(MMG5_pMesh, MMG5_pSol, int, MMG5_int *, int8_t)
Definition: movpt_2d.c:53
int MMG2D_split3_sim(MMG5_pMesh, MMG5_pSol, MMG5_int, MMG5_int vx[3])
Definition: split_2d.c:592
#define MMG2D_LSHRT
int MMG2D_adptri(MMG5_pMesh mesh, MMG5_pSol met)
Definition: mmg2d1.c:550
MMG5_int MMG2D_anaelt(MMG5_pMesh mesh, MMG5_pSol met, int typchk)
Definition: mmg2d1.c:111
MMG5_int MMG2D_movtri(MMG5_pMesh mesh, MMG5_pSol met, int maxit, int8_t improve)
Definition: mmg2d1.c:755
int MMG2D_anatri(MMG5_pMesh mesh, MMG5_pSol met, int8_t typchk)
Definition: mmg2d1.c:40
int MMG2D_dichoto(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, MMG5_int *vx)
Definition: mmg2d1.c:360
int MMG2D_adpcol(MMG5_pMesh mesh, MMG5_pSol met)
Definition: mmg2d1.c:696
int MMG2D_mmg2d1n(MMG5_pMesh mesh, MMG5_pSol met)
Definition: mmg2d1.c:819
MMG5_int MMG2D_colelt(MMG5_pMesh mesh, MMG5_pSol met, int typchk)
Definition: mmg2d1.c:437
MMG5_int MMG2D_swpmsh(MMG5_pMesh mesh, MMG5_pSol met, int typchk)
Definition: mmg2d1.c:514
MMG5_int MMG2D_adpspl(MMG5_pMesh mesh, MMG5_pSol met)
Definition: mmg2d1.c:640
#define MG_GEO
#define MG_EOK(pt)
#define MMG5_INCREASE_MEM_MESSAGE()
#define MG_CLR(flag, bit)
#define MG_MAX(a, b)
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
#define MG_SIN(tag)
#define MMG5_TRIA_LMAX
#define MG_GET(flag, bit)
static const uint8_t MMG5_inxt2[6]
#define MG_BDY
#define MG_NOM
#define MG_REF
#define MMG5_DEL_MEM(mesh, ptr)
#define MG_SET(flag, bit)
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
uint8_t noswap
Definition: libmmgtypes.h:546
double hmin
Definition: libmmgtypes.h:518
double hgrad
Definition: libmmgtypes.h:518
uint8_t noinsert
Definition: libmmgtypes.h:546
uint8_t nomove
Definition: libmmgtypes.h:546
double hgradreq
Definition: libmmgtypes.h:518
int8_t fem
Definition: libmmgtypes.h:539
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_int * adja
Definition: libmmgtypes.h:624
double gap
Definition: libmmgtypes.h:608
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
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 flag
Definition: libmmgtypes.h:282
double * m
Definition: libmmgtypes.h:671
int16_t tag[3]
Definition: libmmgtypes.h:342
MMG5_int ref
Definition: libmmgtypes.h:335
MMG5_int flag
Definition: libmmgtypes.h:341
MMG5_int v[3]
Definition: libmmgtypes.h:334