Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
libmmgs_tools.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.h"
37#include "libmmgs_private.h"
39#include "mmgsexterns_private.h"
40#include "mmgexterns_private.h"
41
42
44 if ( (!mesh->info.ani) && ((!met) || (met->size < 6)) ) {
45 MMG5_calelt = MMG5_caltri_iso;
47 MMG5_lenSurfEdg = MMG5_lenSurfEdg_iso;
48 MMG5_compute_meanMetricAtMarkedPoints = MMG5_compute_meanMetricAtMarkedPoints_iso;
49 MMGS_defsiz = MMGS_defsiz_iso;
50 MMGS_gradsiz = MMG5_gradsiz_iso;
51 MMGS_gradsizreq = MMG5_gradsizreq_iso;
52 intmet = intmet_iso;
53 movintpt = movintpt_iso;
54 movridpt = movridpt_iso;
55 }
56 else {
57 /* Force data consistency: if aniso metric is provided, met->size==6 and
58 * info.ani==0; with -A option, met->size==1 and info.ani==1 */
59 met->size = 6;
60 mesh->info.ani = 1;
61
62 /* Set function pointers */
63 if ( (!met->m) && (!mesh->info.optim) && mesh->info.hsiz<=0. ) {
64 MMG5_calelt = MMG5_caltri_iso;
66 MMG5_lenSurfEdg = MMG5_lenSurfEdg_iso;
67 }
68 else {
69 MMG5_calelt = MMG5_caltri_ani;
71 MMG5_lenSurfEdg = MMG5_lenSurfEdg_ani;
72 }
73 MMG5_compute_meanMetricAtMarkedPoints = MMG5_compute_meanMetricAtMarkedPoints_ani;
74 MMGS_defsiz = MMGS_defsiz_ani;
75 MMGS_gradsiz = MMGS_gradsiz_ani;
76 MMGS_gradsizreq = MMG5_gradsizreq_ani;
77 intmet = intmet_ani;
78 movintpt = movintpt_ani;
79 movridpt = movridpt_ani;
80 }
81}
82
83int MMGS_usage(char *prog) {
84
85 /* Common generic options, file options and mode options */
86 MMG5_mmgUsage(prog);
87
88 /* Common parameters (first section) */
90
91 /* Specific options */
92 fprintf(stdout,"-keep-ref preserve initial domain references in level-set mode.\n");
93
94#ifdef USE_SCOTCH
95 fprintf(stdout,"-rn [n] Turn on or off the renumbering using SCOTCH [0/1] \n");
96#endif
97
98 fprintf(stdout,"\n");
99
100 /* Common parameters (second section) */
102
103 /* Common options for advanced users */
105
106 fprintf(stdout,"\n\n");
107
108 return 1;
109}
110
112
114#ifdef USE_SCOTCH
115 fprintf(stdout,"SCOTCH renumbering : enabled\n");
116#else
117 fprintf(stdout,"SCOTCH renumbering : disabled\n");
118#endif
119 fprintf(stdout,"\n\n");
120
121 return 1;
122}
123
124// In ls mode : metric must be provided using -met option (-sol or default is the ls).
125// In adp mode : -sol or -met or default allow to store the metric.
126int MMGS_parsar(int argc,char *argv[],MMG5_pMesh mesh,MMG5_pSol met,MMG5_pSol sol) {
127 MMG5_pSol tmp = NULL;
128 double val;
129 int i,param;
130 char namein[MMG5_FILESTR_LGTH],*endptr;
131
132 /* First step: search if user want to see the default parameters values. */
133 for ( i=1; i< argc; ++i ) {
134 if ( !strcmp(argv[i],"-val") ) {
136 return 0;
137 }
138 else if ( ( !strcmp( argv[ i ],"-?" ) ) || ( !strcmp( argv[ i ],"-h" ) ) ) {
139 MMGS_usage(argv[0]);
140 return 0;
141 }
142 }
143
144 /* Second step: read all other arguments. */
145 i = 1;
146 while ( i < argc ) {
147 if ( *argv[i] == '-' ) {
148 switch(argv[i][1]) {
149 case 'a': /* ridge angle */
150 if ( !strcmp(argv[i],"-ar") ) {
151 if ( i >= argc -1 ) {
152 fprintf(stderr,"\nMissing argument option %s\n",argv[i]);
153 return 0;
154 }
155 else {
156 val = strtof(argv[i+1],&endptr);
157 if ( endptr == &(argv[i+1][strlen(argv[i+1])]) ) {
158 ++i;
160 return 0;
161 }
162 else {
163 /* argument is not a number */
164 fprintf(stderr,"\nMissing argument option %s\n",argv[i]);
165 return 0;
166 }
167 }
168 }
169 break;
170 case 'A': /* anisotropy */
172 return 0;
173 break;
174 case 'f':
175 if ( !strcmp(argv[i],"-f") ) {
176 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-' ) {
177 if ( !MMGS_Set_inputParamName(mesh,argv[i]) )
178 return 0;
179 }
180 else {
181 fprintf(stderr,"\nMissing filename for %s\n",argv[i-1]);
182 MMGS_usage(argv[0]);
183 return 0;
184 }
185 }
186 break;
187 case 'h':
188 param = MMG5_UNSET;
189 if ( i >= argc -1 ) {
190 fprintf(stderr,"\nMissing argument option %s\n",argv[i]);
191 return 0;
192 }
193 else {
194 if ( !strcmp(argv[i],"-hmin") ) {
195 param = MMGS_DPARAM_hmin;
196 }
197 else if ( !strcmp(argv[i],"-hmax") ) {
198 param = MMGS_DPARAM_hmax;
199 }
200 else if ( !strcmp(argv[i],"-hsiz") ) {
201 param = MMGS_DPARAM_hsiz;
202 }
203 else if ( !strcmp(argv[i],"-hausd") ) {
204 param = MMGS_DPARAM_hausd;
205 }
206 else if ( !strcmp(argv[i],"-hgradreq") ) {
207 param = MMGS_DPARAM_hgradreq;
208 }
209 else if ( !strcmp(argv[i],"-hgrad") ) {
210 param = MMGS_DPARAM_hgrad;
211 }
212 else {
213 /* Arg unknown by Mmg: arg starts with -h but is not known */
214 MMGS_usage(argv[0]);
215 return 0;
216 }
217
218 assert ( param != MMG5_UNSET );
219
220 val = strtof(argv[i+1],&endptr);
221 if ( endptr == &(argv[i+1][strlen(argv[i+1])]) ) {
222 ++i;
223 if ( !MMGS_Set_dparameter(mesh,met,param,val) ){
224 return 0;
225 }
226 } else {
227 /* argument is not a number */
228 fprintf(stderr,"\nMissing argument option %s\n",argv[i]);
229 return 0;
230 }
231 }
232
233 break;
234 case 'd':
235 if ( !strcmp(argv[i],"-default") ) {
236 mesh->mark=1;
237 }
238 else {
240 return 0;
241 }
242 break;
243 case 'i':
244 if ( !strcmp(argv[i],"-in") ) {
245 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-') {
246 if ( !MMGS_Set_inputMeshName(mesh, argv[i]) )
247 return 0;
248
250 return 0;
251 }else{
252 fprintf(stderr,"\nMissing filname for %s\n",argv[i-1]);
253 MMGS_usage(argv[0]);
254 return 0;
255 }
256 }
257 else if ( !strcmp(argv[i],"-isoref") && ++i <= argc ) {
259 atoi(argv[i])) )
260 return 0;
261 }
262 else {
263 MMGS_usage(argv[0]);
264 return 0;
265 }
266 break;
267 case 'k':
268 if ( !strcmp(argv[i],"-keep-ref") ) {
270 return 0;
271 }
272 break;
273 case 'l':
274 if ( !strcmp(argv[i],"-ls") ) {
276 return 0;
277
278 if ( i < argc -1 ) {
279 val = strtof(argv[i+1],&endptr);
280 if ( endptr == &(argv[i+1][strlen(argv[i+1])]) ) {
281 ++i;
283 return 0;
284 }
285 }
286 }
287 else if ( !strcmp(argv[i],"-lssurf") ) {
289 return 0;
290
291 if ( i < argc -1 ) {
292 val = strtof(argv[i+1],&endptr);
293 if ( endptr == &(argv[i+1][strlen(argv[i+1])]) ) {
294 ++i;
296 return 0;
297 }
298 }
299 }
300 break;
301 case 'm':
302 if ( !strcmp(argv[i],"-met") ) {
303 if ( !met ) {
304 fprintf(stderr,"\nNo metric structure allocated for %s option\n",
305 argv[i-1]);
306 return 0;
307 }
308 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-' ) {
309 if ( !MMGS_Set_inputSolName(mesh,met,argv[i]) )
310 return 0;
311 }
312 else {
313 fprintf(stderr,"\nMissing filname for %s\n",argv[i-1]);
314 MMGS_usage(argv[0]);
315 return 0;
316 }
317 }
318 else if (!strcmp(argv[i],"-m") ) {
319 if ( ++i < argc && isdigit(argv[i][0]) ) {
320 if ( !MMGS_Set_iparameter(mesh,met,MMGS_IPARAM_mem,atoi(argv[i])) )
321 return 0;
322 }
323 else {
324 fprintf(stderr,"\nMissing argument option %s\n",argv[i-1]);
325 MMGS_usage(argv[0]);
326 return 0;
327 }
328 }
329 break;
330 case 'n':
331 if ( !strcmp(argv[i],"-nr") ) {
333 return 0;
334 }
335 else if ( !strcmp(argv[i],"-nsd") ) {
336 if ( ++i < argc && isdigit(argv[i][0]) ) {
337 if ( !MMGS_Set_iparameter(mesh,met,MMGS_IPARAM_numsubdomain,atoi(argv[i])) )
338 return 0;
339 }
340 else {
341 fprintf(stderr,"\nMissing argument option %s\n",argv[i-1]);
342 MMGS_usage(argv[0]);
343 return 0;
344 }
345 }
346 else if ( !strcmp(argv[i],"-noswap") ) {
348 return 0;
349 }
350 else if( !strcmp(argv[i],"-noinsert") ) {
352 return 0;
353 }
354 else if( !strcmp(argv[i],"-nomove") ) {
356 return 0;
357 }
358 else if ( !strcmp(argv[i],"-nreg") ) {
360 return 0;
361 }
362 else if( !strcmp(argv[i],"-nosizreq") ) {
364 return 0;
365 }
366 }
367 break;
368 case 'o':
369 if ( (!strcmp(argv[i],"-out")) || (!strcmp(argv[i],"-o")) ) {
370 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-') {
371 if ( !MMGS_Set_outputMeshName(mesh,argv[i]) )
372 return 0;
373 }else{
374 fprintf(stderr,"\nMissing filname for %s\n",argv[i-1]);
375 MMGS_usage(argv[0]);
376 return 0;
377 }
378 }
379 else if( !strcmp(argv[i],"-optim") ) {
381 return 0;
382 }
383 else {
384 fprintf(stderr,"\nUnrecognized option %s\n",argv[i]);
385 MMGS_usage(argv[0]);
386 return 0;
387 }
388 break;
389 case 'r':
390 if ( !strcmp(argv[i],"-rmc") ) {
392 return 0;
393 if ( i < argc -1 ) {
394 val = strtof(argv[i+1],&endptr);
395 if ( endptr == &(argv[i+1][strlen(argv[i+1])]) ) {
396 ++i;
398 return 0;
399 }
400 }
401 }
402#ifdef USE_SCOTCH
403 else if ( !strcmp(argv[i],"-rn") ) {
404 if ( ++i < argc ) {
405 if ( isdigit(argv[i][0]) ) {
406 if ( !MMGS_Set_iparameter(mesh,met,MMGS_IPARAM_renum,atoi(argv[i])) )
407 return 0;
408 }
409 else {
410 fprintf(stderr,"\nMissing argument option %s\n",argv[i-1]);
411 MMGS_usage(argv[0]);
412 return 0;
413 }
414 }
415 else {
416 fprintf(stderr,"\nMissing argument option %s\n",argv[i-1]);
417 MMGS_usage(argv[0]);
418 return 0;
419 }
420 }
421#endif
422 else {
423 fprintf(stderr,"\nUnrecognized option %s\n",argv[i]);
424 MMGS_usage(argv[0]);
425 return 0;
426 }
427 break;
428 case 's':
429 if ( !strcmp(argv[i],"-sol") ) {
430 /* For retrocompatibility, store the metric if no sol structure available */
431 tmp = sol ? sol : met;
432 assert(tmp);
433 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-' ) {
434 if ( !MMGS_Set_inputSolName(mesh,tmp,argv[i]) )
435 return 0;
436 }
437 else {
438 fprintf(stderr,"\nMissing filname for %s\n",argv[i-1]);
439 MMGS_usage(argv[0]);
440 return 0;
441 }
442 }
443 break;
444 case 'v':
445 if ( ++i < argc ) {
446 if ( argv[i][0] == '-' || isdigit(argv[i][0]) ) {
447 if ( !MMGS_Set_iparameter(mesh,met,MMGS_IPARAM_verbose,atoi(argv[i])) )
448 return 0;
449 }
450 else
451 i--;
452 }
453 else {
454 fprintf(stderr,"\nMissing argument option %s\n",argv[i-1]);
455 MMGS_usage(argv[0]);
456 return 0;
457 }
458 break;
459 case 'x':
460 if ( !strcmp(argv[i],"-xreg") ) {
462 return 0;
463 if ( i < argc -1 ) {
464 val = strtof(argv[i+1],&endptr);
465 if ( endptr == &(argv[i+1][strlen(argv[i+1])]) ) {
466 ++i;
468 return 0;
469 }
470 }
471 }
472 break;
473 default:
474 fprintf(stderr,"\nUnrecognized option %s\n",argv[i]);
475 MMGS_usage(argv[0]);
476 return 0;
477 }
478 }
479 else {
480 if ( mesh->namein == NULL ) {
481 if ( !MMGS_Set_inputMeshName(mesh,argv[i]) )
482 return 0;
483 if ( mesh->info.imprim == -99 ) {
485 return 0;
486 }
487 }
488 else if ( mesh->nameout == NULL ) {
489 if ( !MMGS_Set_outputMeshName(mesh,argv[i]) )
490 return 0;
491 }
492 else {
493 fprintf(stdout,"\nArgument %s ignored\n",argv[i]);
494 MMGS_usage(argv[0]);
495 return 0;
496 }
497 }
498 i++;
499 }
500
501 /* check file names */
502 if ( mesh->info.imprim == -99 ) {
503 fprintf(stdout,"\n -- PRINT (0 10(advised) -10) ?\n");
504 fflush(stdin);
505 MMG_FSCANF(stdin,"%d",&i);
507 return 0;
508 }
509
510 if ( mesh->namein == NULL ) {
511 fprintf(stdout,"\n -- INPUT MESH NAME ?\n");
512 fflush(stdin);
513 MMG_FSCANF(stdin,"%127s",namein);
514 if ( !MMGS_Set_inputMeshName(mesh,namein) )
515 return 0;
516 }
517
518 if ( mesh->nameout == NULL ) {
519 if ( !MMGS_Set_outputMeshName(mesh,"") )
520 return 0;
521 }
522
523 /* adp mode: if the metric name has been stored in sol, move it in met */
524 if ( met->namein==NULL && sol && sol->namein &&
525 !(mesh->info.iso || mesh->info.isosurf || mesh->info.lag>=0) ) {
527 return 0;
529 }
530
531 /* default : store solution name in iso mode, metric name otherwise */
532 tmp = ( mesh->info.iso || mesh->info.isosurf || mesh->info.lag >=0 ) ? sol : met;
533 assert ( tmp );
534 if ( tmp->namein == NULL ) {
535 if ( !MMGS_Set_inputSolName(mesh,tmp,"") ) { return 0; }
536 }
537 if ( met->nameout == NULL ) {
538 if ( !MMGS_Set_outputSolName(mesh,met,"") )
539 return 0;
540 }
541 return 1;
542}
543
545
546 free(mesh->info.par);
547 mesh->info.npar = 0;
548
549 return 1;
550}
551
553
554 memcpy(&mesh->info,info,sizeof(MMG5_Info));
556 if( mesh->info.mem > 0) {
557 if ( mesh->npmax < mesh->np || mesh->ntmax < mesh->nt ) {
558 return 0;
559 } else if(mesh->info.mem < 39)
560 return 0;
561 }
562 return 1;
563}
564
566
567 memcpy(info,&mesh->info,sizeof(MMG5_Info));
568 return;
569}
570
572 MMG5_pTria pt,pt1;
573 MMG5_pEdge ped;
574 MMG5_int *adja,k,j,iel;
575 int i,i1,i2;
576
577 *nb_edges = 0;
578 if ( mesh->tria ) {
579 /* Create the triangle adjacency if needed */
580 if ( !mesh->adja ) {
581 if ( !MMGS_hashTria(mesh) ) {
582 fprintf(stderr,"\n ## Error: %s: unable to create "
583 "adjacency table.\n",__func__);
584 return 0;
585 }
586 }
587
588 /* Count the number of non boundary edges */
589 for ( k=1; k<=mesh->nt; k++ ) {
590 pt = &mesh->tria[k];
591 if ( !MG_EOK(pt) ) continue;
592
593 adja = &mesh->adja[3*(k-1)+1];
594
595 for ( i=0; i<3; i++ ) {
596 /* Do not treat boundary edges */
597 if ( MG_EDG(pt->tag[i]) ) continue;
598
599 iel = adja[i] / 3;
600 assert ( iel != k );
601
602 pt1 = &mesh->tria[iel];
603
604 if ( (!iel) || (pt->ref != pt1->ref) ) {
605 /* Do not treat boundary edges */
606 continue;
607 }
608 if ( k < iel ) {
609 /* Treat edge from the triangle with lowest index */
610 ++(*nb_edges);
611 }
612 }
613 }
614
615 /* Append the non boundary edges to the boundary edges array */
616 if ( mesh->na ) {
617 MMG5_ADD_MEM(mesh,(*nb_edges)*sizeof(MMG5_Edge),"non boundary edges",
618 printf(" Exit program.\n");
619 return 0);
620 MMG5_SAFE_RECALLOC(mesh->edge,(mesh->na+1),(mesh->na+(*nb_edges)+1),
621 MMG5_Edge,"non bdy edges arrray",return 0);
622 }
623 else {
624 MMG5_ADD_MEM(mesh,((*nb_edges)+1)*sizeof(MMG5_Edge),"non boundary edges",
625 printf(" Exit program.\n");
626 return 0);
627 MMG5_SAFE_RECALLOC(mesh->edge,0,(*nb_edges)+1,
628 MMG5_Edge,"non bdy edges arrray",return 0);
629 }
630
631 j = mesh->na+1;
632 for ( k=1; k<=mesh->nt; k++ ) {
633 pt = &mesh->tria[k];
634 if ( !MG_EOK(pt) ) continue;
635
636 adja = &mesh->adja[3*(k-1)+1];
637
638 for ( i=0; i<3; i++ ) {
639 /* Do not treat boundary edges */
640 if ( MG_EDG(pt->tag[i]) ) continue;
641
642 i1 = MMG5_inxt2[i];
643 i2 = MMG5_iprv2[i];
644 iel = adja[i] / 3;
645 assert ( iel != k );
646
647 pt1 = &mesh->tria[iel];
648
649 if ( (!iel) || (pt->ref != pt1->ref) ) {
650 /* Do not treat boundary edges */
651 continue;
652 }
653 if ( k < iel ) {
654 /* Treat edge from the triangle with lowest index */
655 ped = &mesh->edge[j++];
656 assert ( ped );
657 ped->a = pt->v[i1];
658 ped->b = pt->v[i2];
659 ped->ref = pt->edg[i];
660 }
661 }
662 }
663 }
664 return 1;
665}
666
667int MMGS_Get_nonBdyEdge(MMG5_pMesh mesh, MMG5_int* e0, MMG5_int* e1, MMG5_int* ref, MMG5_int idx) {
668 MMG5_pEdge ped;
669 size_t na_tot=0;
670 char *ptr_c = (char*)mesh->edge;
671
672 if ( !mesh->edge ) {
673 fprintf(stderr,"\n ## Error: %s: edge array is not allocated.\n"
674 " Please, call the MMGS_Get_numberOfNonBdyEdges function"
675 " before the %s one.\n",
676 __func__,__func__);
677 return 0;
678 }
679
680 ptr_c = ptr_c-sizeof(size_t);
681 na_tot = *((size_t*)ptr_c);
682
683 if ( (size_t)mesh->namax==na_tot ) {
684 fprintf(stderr,"\n ## Error: %s: no internal edge.\n"
685 " Please, call the MMGS_Get_numberOfNonBdyEdges function"
686 " before the %s one and check that the number of internal"
687 " edges is non null.\n",
688 __func__,__func__);
689 }
690
691 if ( (size_t)mesh->namax+idx > na_tot ) {
692 fprintf(stderr,"\n ## Error: %s: Can't get the internal edge of index %" MMG5_PRId "."
693 " Index must be between 1 and %zu.\n",
694 __func__,idx,na_tot-(size_t)mesh->namax);
695 }
696
697 ped = &mesh->edge[mesh->na+idx];
698
699 *e0 = ped->a;
700 *e1 = ped->b;
701
702 if ( ref != NULL ) {
703 *ref = mesh->edge[mesh->na+idx].ref;
704 }
705
706 return 1;
707}
708
709int MMGS_Get_adjaTri(MMG5_pMesh mesh, MMG5_int kel, MMG5_int listri[3]) {
710
711 if ( ! mesh->adja ) {
712 if (! MMGS_hashTria(mesh))
713 return 0;
714 }
715
716 listri[0] = mesh->adja[3*(kel-1)+1]/3;
717 listri[1] = mesh->adja[3*(kel-1)+2]/3;
718 listri[2] = mesh->adja[3*(kel-1)+3]/3;
719
720 return 1;
721}
722
723int MMGS_Get_adjaVerticesFast(MMG5_pMesh mesh, MMG5_int ip,MMG5_int start, MMG5_int lispoi[MMGS_LMAX])
724{
725 MMG5_pTria pt;
726 MMG5_int k,prevk,*adja;
727 int i,i1,i2,iploc,nbpoi;
728
729 pt = &mesh->tria[start];
730
731 for ( iploc=0; iploc<3; ++iploc ) {
732 if ( pt->v[iploc] == ip ) break;
733 }
734
735 assert(iploc!=3);
736
737 k = start;
738 i = iploc;
739 nbpoi = 0;
740 do {
741 if ( nbpoi == MMGS_LMAX ) {
742 fprintf(stderr,"\n ## Warning: %s: unable to compute adjacent"
743 " vertices of the vertex %" MMG5_PRId ":\nthe ball of point contain too many"
744 " elements.\n",__func__,ip);
745 return 0;
746 }
747 i1 = MMG5_inxt2[i];
748 lispoi[nbpoi] = mesh->tria[k].v[i1];
749 ++nbpoi;
750
751 adja = &mesh->adja[3*(k-1)+1];
752 prevk = k;
753 k = adja[i1] / 3;
754 i = adja[i1] % 3;
755 i = MMG5_inxt2[i];
756 }
757 while ( k && k != start );
758
759 if ( k > 0 ) return nbpoi;
760
761 /* store the last point of the boundary triangle */
762 if ( nbpoi == MMGS_LMAX ) {
763 fprintf(stderr,"\n ## Warning: %s: unable to compute adjacent vertices of the"
764 " vertex %" MMG5_PRId ":\nthe ball of point contain too many elements.\n",
765 __func__,ip);
766 return 0;
767 }
768 i1 = MMG5_inxt2[i1];
769 lispoi[nbpoi] = mesh->tria[prevk].v[i1];
770 ++nbpoi;
771
772 /* check if boundary hit */
773 k = start;
774 i = iploc;
775 do {
776 adja = &mesh->adja[3*(k-1)+1];
777 i2 = MMG5_iprv2[i];
778 k = adja[i2] / 3;
779 if ( k == 0 ) break;
780
781 if ( nbpoi == MMGS_LMAX ) {
782 fprintf(stderr,"\n ## Warning: %s: unable to compute adjacent vertices of the"
783 " vertex %" MMG5_PRId ":\nthe ball of point contain too many elements.\n",
784 __func__,ip);
785 return 0;
786 }
787 i = adja[i2] % 3;
788 lispoi[nbpoi] = mesh->tria[k].v[i];
789 ++nbpoi;
790
791 i = MMG5_iprv2[i];
792 }
793 while ( k );
794
795 return nbpoi;
796}
797
809static inline
811 MMG5_int k;
812 int i,ier;
813
814 assert ( mesh->info.optim );
815
816 /* Detect points not used by the mesh */
817 ++mesh->base;
818
819#ifndef NDEBUG
820 for (k=1; k<=mesh->np; k++) {
821 assert ( mesh->point[k].flag < mesh->base );
822 }
823#endif
824
825 for (k=1; k<=mesh->nt; k++) {
826 MMG5_pTria ptt = &mesh->tria[k];
827 if ( !MG_EOK(ptt) ) continue;
828
829 for (i=0; i<3; i++) {
830 mesh->point[ptt->v[i]].flag = mesh->base;
831 }
832 }
833
834 /* Compute hmin/hmax on unflagged points and truncate the metric */
835 if ( !ani ) {
837 }
838 else {
839 MMG5_solTruncature_ani = MMG5_3dSolTruncature_ani;
841 }
842
843 return ier;
844}
845
846
860 MMG5_pTria ptt;
861 MMG5_pPoint p1,p2;
862 double ux,uy,uz,dd;
863 MMG5_int k,ipa,ipb;
864 int i,type;
865 //We guess that we have less than INT32_MAX edges
866 // passing through each point
867 int *mark;
868
869 MMG5_SAFE_CALLOC(mark,mesh->np+1,int,return 0);
870
871 /* Memory alloc */
872 if ( met->size!=1 ) {
873 fprintf(stderr,"\n ## Error: %s: unexpected size of metric: %d.\n",
874 __func__,met->size);
875 return 0;
876 }
877
878 type = 1;
879 if ( !MMGS_Set_solSize(mesh,met,MMG5_Vertex,mesh->np,type) )
880 return 0;
881
882 /* Travel the triangles edges and add the edge contribution to edges
883 * extermities */
884 for (k=1; k<=mesh->nt; k++) {
885 ptt = &mesh->tria[k];
886 if ( !MG_EOK(ptt) ) continue;
887
888 for (i=0; i<3; i++) {
889 ipa = ptt->v[i];
890 ipb = ptt->v[MMG5_inxt2[i]];
891 p1 = &mesh->point[ipa];
892 p2 = &mesh->point[ipb];
893
894 ux = p1->c[0] - p2->c[0];
895 uy = p1->c[1] - p2->c[1];
896 uz = p1->c[2] - p2->c[2];
897 dd = sqrt(ux*ux + uy*uy + uz*uz);
898
899 met->m[ipa] += dd;
900 mark[ipa]++;
901 met->m[ipb] += dd;
902 mark[ipb]++;
903 }
904 }
905
906 /* vertex size */
907 for (k=1; k<=mesh->np; k++) {
908 if ( !mark[k] ) {
909 continue;
910 }
911 else
912 met->m[k] = met->m[k] / (double)mark[k];
913 }
914
915 MMG5_SAFE_FREE(mark);
916
918
919 return 1;
920}
921
938static inline
939int MMGS_unitTensor_3D( MMG5_pMesh mesh,MMG5_int k,int i,MMG5_pPoint p1,double *m) {
940 MMG5_int list[MMGS_LMAX+2];
941 int ilist,j;
942 int8_t open;
943
945 ilist = MMG5_boulet(mesh,k,i,list,1,&open);
946 if ( ilist < 1 ) {
947 fprintf(stderr,"\n ## Error: %s: unable to compute ball of point.\n",
948 __func__);
949 return 0;
950 }
951
953 if ( (!MG_SIN(p1->tag)) && (MG_GEO & p1->tag) && open ) {
954 /* MG_GEO point along an open boundary: we want to compute the 2D unit
955 * tensor */
956 return 0;
957 }
958
959 for ( j=0; j<6; ++j ) {
960 m[j] = 0.;
961 }
962
963 for ( j=0; j<ilist; ++j ) {
964 /* Compute euclidean edge length */
965 double u[3];
966 MMG5_int iel = list[j] / 3;
967 int8_t i1 = list[j] % 3;
968 int8_t i2 = MMG5_inxt2[i1];
969
970 MMG5_pTria ptt = &mesh->tria[iel];
971 MMG5_pPoint p2 = &mesh->point[ptt->v[i2]];
972
973 u[0] = p1->c[0] - p2->c[0];
974 u[1] = p1->c[1] - p2->c[1];
975 u[2] = p1->c[2] - p2->c[2];
976
977 m[0] += u[0]*u[0];
978 m[1] += u[0]*u[1];
979 m[2] += u[0]*u[2];
980 m[3] += u[1]*u[1];
981 m[4] += u[1]*u[2];
982 m[5] += u[2]*u[2];
983 }
984
985 double tensordot[6];
986 int ier = MMG5_invmat(m,tensordot);
987
988 /* Invmat make the assumtion that input matrix is invertible (always the case
989 * normally). Here, if all edges belongs to the same plane, it is not the case
990 * so we have to check the values of the resulting matrix even if invmat
991 * succeed */
992 if ( ier ) {
993 for ( j=0; j<6; ++j ) {
994 if ( !isfinite(tensordot[j]) ) {
995 ier = 0;
996 break;
997 }
998 }
999 }
1000
1001 if ( ier ) {
1002 double lambda[3],vp[3][3];
1003 if ( !MMG5_eigenv3d(1,tensordot,lambda,vp) ) {
1004 ier = 0;
1005 }
1006 else if ( (!isfinite(lambda[0])) || (!isfinite(lambda[1])) || (!isfinite(lambda[2])) ) {
1007 ier = 0;
1008 }
1009 else if ( lambda[0]<=0 || lambda[1]<=0 || lambda[2]<=0 ) {
1010 ier = 0;
1011 }
1012 }
1013
1014 /* Non invertible matrix: put FLT_MIN waiting for a treatment later */
1015 if ( !ier ) {
1016 m[0] = FLT_MIN;
1017 m[1] = 0;
1018 m[2] = 0;
1019 m[3] = FLT_MIN;
1020 m[4] = 0;
1021 m[5] = FLT_MIN;
1022 return 0;
1023 }
1024
1025 double dd = (double)ilist/3.;
1026 for ( j=0; j<6; ++j ) {
1027 m[j] = dd*tensordot[j];
1028 }
1029
1030 return 1;
1031}
1032
1049static inline
1051 int ilist,double r[3][3],double *lispoi,double n[3]) {
1052 MMG5_pTria ptt;
1053 MMG5_pPoint p2;
1054 double ux,uy,uz;
1055 MMG5_int *adja,kold;
1056 int jold,i1;
1057
1058 if ( !MMG5_rotmatrix(n,r) ) {
1059 return 0;
1060 }
1061
1062 /* Enumeration of the ball starting from a boundary */
1063 MMG5_int iel = k;
1064 int j = i;
1065 do {
1066 adja = &mesh->adja[3*(iel-1)+1];
1067 i1 = MMG5_iprv2[j];
1068 kold = iel;
1069 jold = j;
1070 iel = adja[i1] / 3;
1071 j = (int)adja[i1] % 3;
1072 j = MMG5_iprv2[j];
1073 }
1074 // Remark: here the test k!=start is a security bound: theorically it is
1075 // useless but in case of bad edge tag, it ensure that the loop is not
1076 // infinite.
1077 while ( iel && iel != k );
1078
1079 iel = kold;
1080 j = jold;
1081 int idx = 0;
1082 do {
1083 ptt = &mesh->tria[iel];
1084 // here, p1 == &mesh->point[ptt->v[j]]
1085
1086 adja = &mesh->adja[3*(iel-1)+1];
1087 i1 = MMG5_inxt2[j];
1088 p2 = &mesh->point[ptt->v[i1]];
1089
1090 ux = p2->c[0] - p0->c[0];
1091 uy = p2->c[1] - p0->c[1];
1092 uz = p2->c[2] - p0->c[2];
1093
1094 lispoi[3*idx+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
1095 lispoi[3*idx+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
1096 lispoi[3*idx+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
1097
1098 iel = adja[i1] / 3;
1099 j = (int)adja[i1] % 3;
1100 j = MMG5_inxt2[j];
1101
1102 ++idx;
1103 }
1104 while ( iel );
1105
1106 /* last point : the half-ball is open : ilist tria, and ilist +1 points ;
1107 lists are enumerated in direct order */
1108 i1 = MMG5_inxt2[i1];
1109 p2 = &mesh->point[ptt->v[i1]];
1110
1111 ux = p2->c[0] - p0->c[0];
1112 uy = p2->c[1] - p0->c[1];
1113 uz = p2->c[2] - p0->c[2];
1114
1115 lispoi[3*idx+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
1116 lispoi[3*idx+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
1117 lispoi[3*idx+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
1118
1119 assert ( idx == ilist );
1120
1121 /* Check all projections over tangent plane. */
1122 for (j=0; j<ilist; j++) {
1123 double area = lispoi[3*j+1]*lispoi[3*(j+1)+2] - lispoi[3*j+2]*lispoi[3*(j+1)+1];
1124 if ( area <= 0.0 ) {
1125 fprintf(stderr,"\n ## Error: %s: unable to compute ball rotation.\n",
1126 __func__);
1127 return 0;
1128 }
1129 }
1130 return 1;
1131}
1132
1147static inline
1149 double *m,double isqhmax) {
1150 MMG5_pTria ptt;
1151 double r[3][3],lispoi[3*MMGS_LMAX+1],b0[3],b1[3],b2[3],dd;
1152 MMG5_int list[MMGS_LMAX+2];
1153 int ilist,j;
1154 int8_t opn;
1155
1158 /* Possible improvement: if we have called MMGS_unitTensor_3D previously,
1159 * boulet is already computed */
1160 ilist = MMG5_boulet(mesh,k,i,list,1,&opn);
1161 if ( ilist < 1 ) {
1162 fprintf(stderr,"\n ## Error: %s: unable to compute ball of point.\n",
1163 __func__);
1164 return 0;
1165 }
1166
1167
1170 /* If point \a p1 is corner or required we compute the normal
1171 at point as the * mean of the normals at triangles of the ball. If the point
1172 is ridge (can be * non-manifold), we compute it as the mean of n1 and n2. In
1173 the other cases, * the normal is stored in p1->n */
1174 double nn[3] = {0.,0.,0.};
1175 if ( MG_SIN(p1->tag) ) {
1176 /* Corner or required point: compute the normal at point as the mean of
1177 * normals at triangles */
1178 for ( j=0; j<ilist; ++j ) {
1179 ptt = &mesh->tria[list[j]/3];
1180 double n[3];
1181
1182 MMG5_nortri(mesh,ptt,n);
1183 nn[0] += n[0]; nn[1] += n[1]; nn[2] += n[2];
1184 }
1185 /* normalization */
1186 dd = nn[0]*nn[0] + nn[1]*nn[1] + nn[2]*nn[2];
1187 if ( dd > MMG5_EPSD2 ) {
1188 dd = 1.0 / sqrt(dd);
1189 nn[0] *= dd;
1190 nn[1] *= dd;
1191 nn[2] *= dd;
1192 }
1193 }
1194 else if ( MG_GEO & p1->tag ) {
1195 if ( MG_NOM & p1->tag ) {
1196 fprintf(stderr,"\n ## Error: %s: we should not pass here with a "
1197 "non-manifold point: it sould always be posible to compute the 3D"
1198 " unit tensor on such points.\n",
1199 __func__);
1200 return 0;
1201 }
1202 /* Manifold ridge point: compute the normal as the mean of the 2 computed
1203 * normals */
1204 assert ( p1->xp );
1205 nn[0] = mesh->xpoint[p1->xp].n1[0] + mesh->xpoint[p1->xp].n2[0];
1206 nn[1] = mesh->xpoint[p1->xp].n1[1] + mesh->xpoint[p1->xp].n2[1];
1207 nn[2] = mesh->xpoint[p1->xp].n1[2] + mesh->xpoint[p1->xp].n2[2];
1208
1209 /* normalization */
1210 dd = nn[0]*nn[0] + nn[1]*nn[1] + nn[2]*nn[2];
1211 if ( dd > MMG5_EPSD2 ) {
1212 dd = 1.0 / sqrt(dd);
1213 nn[0] *= dd;
1214 nn[1] *= dd;
1215 nn[2] *= dd;
1216 }
1217 }
1218 else if ( MG_REF & p1->tag ) {
1219 /* Reference point: normal is stored in the xpoint */
1220 assert ( p1->xp );
1221 nn[0] = mesh->xpoint[p1->xp].n1[0];
1222 nn[1] = mesh->xpoint[p1->xp].n1[1];
1223 nn[2] = mesh->xpoint[p1->xp].n1[2];
1224 }
1225 else {
1226 /* Regular point: normal is stored in the field n of the point */
1227 nn[0] = p1->n[0]; nn[1] = p1->n[1]; nn[2] = p1->n[2];
1228 }
1229
1232 if ( opn ) {
1233 if ( !MMGS_surfopenballRotation(mesh,p1,k,i,ilist,r,lispoi,nn) ) {
1234 fprintf(stderr,"\n ## Error: %s: unable to compute opened ball rotation.\n",
1235 __func__);
1236 return 0;
1237 }
1238 }
1239 else {
1240 if ( !MMGS_surfballRotation(mesh,p1,list,ilist,r,lispoi,nn) ) {
1241 fprintf(stderr,"\n ## Error: %s: unable to compute ball rotation.\n",
1242 __func__);
1243 return 0;
1244 }
1245 }
1246
1248 double tensordot[3];
1249 tensordot[0] = 0.;
1250 tensordot[1] = 0.;
1251 tensordot[2] = 0.;
1252
1253 for ( j=0; j<ilist; ++j ) {
1254 /* Compute the 2D metric tensor from the projection of the vectors on
1255 * the tangent plane */
1256 tensordot[0] += lispoi[3*j+1]*lispoi[3*j+1];
1257 tensordot[1] += lispoi[3*j+1]*lispoi[3*j+2];
1258 tensordot[2] += lispoi[3*j+2]*lispoi[3*j+2];
1259 }
1260
1261 /* Metric = nedges/dim * inv (sum(tensor_dot(edges,edges))) */
1262 dd = 1./(tensordot[0]*tensordot[2] - tensordot[1]*tensordot[1]);
1263 dd *= (double)ilist/2.;
1264
1265 double tmp = tensordot[0];
1266
1267 tensordot[0] = dd*tensordot[2];
1268 tensordot[1] = -dd*tensordot[1];
1269 tensordot[2] = dd*tmp;
1270
1271#ifndef NDEBUG
1272 /* Check 2D metric */
1273 double lambda[2],vp[2][2];
1274 MMG5_eigensym(tensordot,lambda,vp);
1275
1276 assert (lambda[0] > 0. && lambda[1] > 0. && "Negative eigenvalue");
1277
1278 /* Normally the case where the point belongs to only 2 colinear points is
1279 impossible */
1280 assert (isfinite(lambda[0]) && isfinite(lambda[1]) && "wrong eigenvalue");
1281#endif
1282
1283 /* At this point, tensordot (with 0 replaced by isqhmax in the z
1284 direction) is the desired metric, except it is expressed in the rotated
1285 canonical basis, that is tensordot = R * metric in cb * ^t R, so metric
1286 in cb = ^tR*intm*R */
1287 // intm = intm[0] intm[1] 0
1288 // intm[1] intm[2] 0
1289 // 0 0 isqhmax
1290
1291 /* b0 and b1 serve now for nothing : let them be the lines of matrix intm*R */
1292
1293 // Remark: here, we put a 'fake' value along the normal direction but we can't
1294 // use a nan or inf value because it impacts the computation of the rotation
1295 // for the other directions
1296 b0[0] = tensordot[0]*r[0][0] + tensordot[1]*r[1][0];
1297 b0[1] = tensordot[0]*r[0][1] + tensordot[1]*r[1][1];
1298 b0[2] = tensordot[0]*r[0][2] + tensordot[1]*r[1][2];
1299 b1[0] = tensordot[1]*r[0][0] + tensordot[2]*r[1][0];
1300 b1[1] = tensordot[1]*r[0][1] + tensordot[2]*r[1][1];
1301 b1[2] = tensordot[1]*r[0][2] + tensordot[2]*r[1][2];
1302
1303 b2[0] = isqhmax*r[2][0];
1304 b2[1] = isqhmax*r[2][1];
1305 b2[2] = isqhmax*r[2][2];
1306
1307 m[0] = r[0][0] * b0[0] + r[1][0] * b1[0] + r[2][0] * b2[0];
1308 m[1] = r[0][0] * b0[1] + r[1][0] * b1[1] + r[2][0] * b2[1];
1309 m[2] = r[0][0] * b0[2] + r[1][0] * b1[2] + r[2][0] * b2[2];
1310
1311 m[3] = r[0][1] * b0[1] + r[1][1] * b1[1] + r[2][1] * b2[1];
1312 m[4] = r[0][1] * b0[2] + r[1][1] * b1[2] + r[2][1] * b2[2];
1313
1314 m[5] = r[0][2] * b0[2] + r[1][2] * b1[2] + r[2][2] * b2[2];
1315
1316 return 1;
1317}
1318
1319
1320
1335 MMG5_pTria ptt;
1336 MMG5_pPoint p1;
1337 double *m,tensordot[6];
1338 MMG5_int k,iadr,ip;
1339 int i,j,type;
1340
1341 /* Memory alloc */
1342 if ( met->size!=6 ) {
1343 fprintf(stderr,"\n ## Error: %s: unexpected size of metric: %d.\n",
1344 __func__,met->size);
1345 return 0;
1346 }
1347
1348 type = 3;
1349 if ( !MMGS_Set_solSize(mesh,met,MMG5_Vertex,mesh->np,type) ) {
1350 fprintf(stderr,"\n ## Error: %s: unable to allocate metric.\n",
1351 __func__);
1352 return 0;
1353 }
1354
1356 ++mesh->base;
1357
1358#ifndef NDEBUG
1359 for (k=1; k<=mesh->np; k++) {
1360 p1 = &mesh->point[k];
1361 assert ( p1->flag < mesh->base );
1362 }
1363#endif
1364
1365 double isqhmax = 1./(MMG5_HMAXCOE*MMG5_HMAXCOE);
1366
1371 /* mark array will be used only for non-manifold points */
1372 int *mark;
1373 MMG5_SAFE_CALLOC(mark,mesh->np+1,int,return 0);
1374
1375 for (k=1; k<=mesh->nt; k++) {
1376 ptt = &mesh->tria[k];
1377 if ( !MG_EOK(ptt) ) continue;
1378
1379 for (i=0; i<3; i++) {
1380 MMG5_int ipa = ptt->v[MMG5_iprv2[i]];
1381 MMG5_int ipb = ptt->v[MMG5_inxt2[i]];
1382 p1 = &mesh->point[ipa];
1383 MMG5_pPoint p2 = &mesh->point[ipb];
1384
1385 if ( (!(MG_NOM & p1->tag)) && !(MG_NOM & p2->tag) ) {
1386 continue;
1387 }
1388
1389 double u[3];
1390 u[0] = p1->c[0] - p2->c[0];
1391 u[1] = p1->c[1] - p2->c[1];
1392 u[2] = p1->c[2] - p2->c[2];
1393
1394 tensordot[0] = u[0]*u[0];
1395 tensordot[1] = u[0]*u[1];
1396 tensordot[2] = u[0]*u[2];
1397 tensordot[3] = u[1]*u[1];
1398 tensordot[4] = u[1]*u[2];
1399 tensordot[5] = u[2]*u[2];
1400
1401 if ( MG_NOM & p1->tag ) {
1402 iadr = 6*ipa;
1403 for ( j=0; j<6; ++j ) {
1404 met->m[iadr+j] += tensordot[j];
1405 }
1406 mark[ipa]++;
1407 }
1408
1409 if ( MG_NOM & p2->tag ) {
1410 iadr = 6*ipb;
1411 for ( j=0; j<6; ++j ) {
1412 met->m[iadr+j] += tensordot[j];
1413 }
1414 mark[ipb]++;
1415 }
1416 }
1417 }
1418
1419 for (k=1; k<=mesh->np; k++) {
1420 p1 = &mesh->point[k];
1421 if ( !mark[k] ) {
1422 continue;
1423 }
1424
1425 p1->flag = mesh->base;
1426
1427 /* Metric = nedges/dim * inv (sum(tensor_dot(edges,edges))).
1428 * sum(tensor_dot) is stored in sol->m so reuse tensordot to
1429 * compute M. */
1430 iadr = 6*k;
1431 if ( !MMG5_invmat(met->m+iadr,tensordot) ) {
1432 /* Non invertible matrix: impose isqhmax, it will be truncated by hmax
1433 * later */
1434 fprintf(stdout, " ## Warning: %s: %d: non invertible matrix."
1435 " Impose hmax size at point\n",__func__,__LINE__);
1436 met->m[iadr+0] = isqhmax;
1437 met->m[iadr+2] = 0;
1438 met->m[iadr+3] = isqhmax;
1439 met->m[iadr+4] = 0;
1440 met->m[iadr+5] = isqhmax;
1441 continue;
1442 }
1443
1444 double dd = (double)mark[k]/3.;
1445
1446 for ( j=0; j<6; ++j ) {
1447 met->m[iadr+j] = dd*tensordot[j];
1448 }
1449 }
1450
1451 MMG5_SAFE_FREE(mark);
1452
1453
1454 /* Step 2: travel the triangles to treat the other type of points: On corner
1455 * or ridge point, try to compute 3D unit tensor, on other points, projection
1456 * of the bal of point onto the tangent plane and computation of the 2D unit
1457 * tensor. */
1458 for (k=1; k<=mesh->nt; k++) {
1459 ptt = &mesh->tria[k];
1460 if ( !MG_EOK(ptt) ) continue;
1461
1462 for (i=0; i<3; i++) {
1463 ip = ptt->v[i];
1464
1465 p1 = &mesh->point[ip];
1466 if ( p1->flag == mesh->base ) {
1467 continue;
1468 }
1469
1470 iadr = 6*ip;
1471 m = &met->m[iadr];
1472
1473 if ( MG_CRN & p1->tag ) {
1480 int ier = MMGS_unitTensor_3D( mesh, k, i, p1, m);
1481
1482 if ( !ier ) {
1483 /* Non invertible matrix: compute the 2D unit tensor */
1484 ier = MMGS_unitTensor_2D( mesh, k, i, p1, m, isqhmax);
1485 }
1486
1487 if ( !ier ) {
1488 fprintf(stderr,"\n ## Error: %s: unable to compute anisotropic unit"
1489 " tensor at corner point %"MMG5_PRId".\n",__func__,MMGS_indPt(mesh,ip));
1490 return 0;
1491 }
1492 p1->flag = mesh->base;
1493 }
1494 else if ( MG_REQ & p1->tag ) {
1497 if ( ! MMGS_unitTensor_2D( mesh, k, i, p1, m, isqhmax) ) {
1498 fprintf(stderr,"\n ## Error: %s: unable to compute anisotropic unit"
1499 " tensor at required point %"MMG5_PRId".\n",__func__,MMGS_indPt(mesh,ip));
1500 return 0;
1501 }
1502 p1->flag = mesh->base;
1503 }
1504 else if ( p1->tag & MG_GEO && !(p1->tag & MG_NOM) ) {
1508 int ier = MMGS_unitTensor_3D( mesh, k, i, p1, m);
1509
1510 if ( !ier ) {
1511 /* Non invertible matrix: compute the 2D unit tensor */
1512 ier = MMGS_unitTensor_2D( mesh, k, i, p1, m, isqhmax);
1513 }
1514
1515 if ( !ier ) {
1516 fprintf(stderr,"\n ## Error: %s: unable to compute anisotropic unit"
1517 " tensor at ridge point %"MMG5_PRId".\n",__func__,
1518 MMGS_indPt(mesh,ip));
1519 }
1520 p1->flag = mesh->base;
1521 }
1522 else {
1526 assert ( !(MG_NOM & p1->tag) ); // non-manifold points should have been already treated
1527
1528 if ( ! MMGS_unitTensor_2D( mesh, k, i, p1, m, isqhmax) ) {
1529 fprintf(stderr,"\n ## Error: %s: unable to compute anisotropic unit"
1530 " tensor at required point %"MMG5_PRId".\n",__func__,
1531 MMGS_indPt(mesh,ip));
1532 return 0;
1533 }
1534 p1->flag = mesh->base;
1535 }
1536 /* Check metric */
1537 double lambda[3],vp[3][3];
1538 if (!MMG5_eigenv3d(1,met->m+iadr,lambda,vp) ) {
1539 fprintf(stdout, " ## Warning: %s: %d: non diagonalizable metric.",
1540 __func__,__LINE__);
1541 }
1542
1543 assert ( lambda[0] > 0. && lambda[1] > 0. && lambda[2] > 0.
1544 && "Negative eigenvalue" );
1545 assert ( isfinite(lambda[0]) && isfinite(lambda[1]) && isfinite(lambda[2])
1546 && "Infinite eigenvalue" );
1547 }
1548 }
1549
1551#ifndef NDEBUG
1552 for (k=1; k<=mesh->np; k++) {
1553 p1 = &mesh->point[k];
1554 if ( p1->flag != mesh->base ) {
1555 continue;
1556 }
1557 iadr = 6*k;
1558
1559 /* Check metric */
1560 double lambda[3],vp[3][3];
1561 if (!MMG5_eigenv3d(1,met->m+iadr,lambda,vp) ) {
1562 fprintf(stdout, " ## Warning: %s: %d: non diagonalizable metric.",
1563 __func__,__LINE__);
1564 }
1565
1566 assert ( lambda[0] > 0. && lambda[1] > 0. && lambda[2] > 0.
1567 && "Negative eigenvalue" );
1568 assert ( isfinite(lambda[0]) && isfinite(lambda[1]) && isfinite(lambda[2])
1569 && "Infinite eigenvalue" );
1570 }
1571#endif
1572
1575
1576 return 1;
1577}
1578
1580 double hsiz;
1581 int type;
1582
1583 /* Set solution size */
1584 if ( mesh->info.ani ) {
1585 met->size = 6;
1586 type = 3;
1587 }
1588 else {
1589 met->size = 1;
1590 type = 1;
1591 }
1592
1593 /* Memory alloc */
1594 if ( !MMGS_Set_solSize(mesh,met,MMG5_Vertex,mesh->np,type) )
1595 return 0;
1596
1597 if ( !MMG5_Compute_constantSize(mesh,met,&hsiz) )
1598 return 0;
1599
1600 mesh->info.hsiz = hsiz;
1601
1602 MMG5_Set_constantSize(mesh,met,hsiz);
1603
1604 return 1;
1605}
1606
1607int MMGS_Compute_eigenv(double m[6],double lambda[3],double vp[3][3]) {
1608
1609 return MMG5_eigenv3d(1,m,lambda,vp);
1610
1611}
1612
1614
1615 /* sol */
1616 if ( !sol ) return;
1617
1618 if ( sol->m )
1619 MMG5_DEL_MEM(mesh,sol->m);
1620
1621 if ( sol->namein ) {
1623 }
1624
1625 if ( sol->nameout ) {
1627 }
1628
1629 memset ( sol, 0x0, sizeof(MMG5_Sol) );
1630
1631 /* Reset state to a scalar status */
1632 sol->dim = 3;
1633 sol->ver = 2;
1634 sol->size = 1;
1635 sol->type = 1;
1636
1637 return;
1638}
1639
1641
1642 return MMG5_Clean_isoEdges(mesh);
1643}
int MMG5_Compute_constantSize(MMG5_pMesh mesh, MMG5_pSol met, double *hsiz)
void MMG5_Set_constantSize(MMG5_pMesh mesh, MMG5_pSol met, double hsiz)
int MMGS_Set_iparameter(MMG5_pMesh mesh, MMG5_pSol sol, int iparam, MMG5_int val)
set an integer parameter of the remesher
int MMGS_Set_inputMeshName(MMG5_pMesh mesh, const char *meshin)
Set the name of the input mesh.
int MMGS_Set_inputParamName(MMG5_pMesh mesh, const char *fparamin)
Set the name of the input parameter file.
int MMGS_Set_inputSolName(MMG5_pMesh mesh, MMG5_pSol sol, const char *solin)
Set the name of the input solution file.
int MMGS_Set_solSize(MMG5_pMesh mesh, MMG5_pSol sol, int typEntity, MMG5_int np, int typSol)
Initialize an array of solution fields: set dimension, types and number of fields.
int MMGS_Set_outputMeshName(MMG5_pMesh mesh, const char *meshout)
Set the name of the output mesh file.
int MMGS_Set_dparameter(MMG5_pMesh mesh, MMG5_pSol sol, int dparam, double val)
set a real-valued parameter of the remesher
int MMGS_Set_outputSolName(MMG5_pMesh mesh, MMG5_pSol sol, const char *solout)
Set the name of the output solution file.
int ier
tmp[*strlen0]
MMG5_pMesh MMG5_pSol * sol
if(!ier) exit(EXIT_FAILURE)
MMG5_pMesh * mesh
int movintpt_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *list, int ilist)
Definition: anisomovpt_s.c:49
int movridpt_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *list, int ilist)
Definition: anisomovpt_s.c:252
int MMG5_gradsizreq_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz.c:2322
int MMG5_compute_meanMetricAtMarkedPoints_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz.c:2205
int MMGS_gradsiz_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz_s.c:835
int MMGS_defsiz_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz_s.c:735
int MMGS_surfballRotation(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_int *list, int ilist, double r[3][3], double *lispoi, double n[3])
Definition: anisosiz_s.c:529
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_eigensym(double m[3], double lambda[2], double vp[2][2])
Definition: eigenv.c:973
int MMG5_eigenv3d(int symmat, double *mat, double lambda[3], double v[3][3])
Find eigenvalues and vectors of a 3x3 matrix.
Definition: eigenv.c:385
MMG5_int MMGS_indPt(MMG5_pMesh mesh, MMG5_int kp)
Definition: gentools_s.c:139
int MMGS_hashTria(MMG5_pMesh mesh)
Definition: hash_s.c:77
static double MMG5_lenSurfEdg_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int ip1, MMG5_int ip2, int8_t isedg)
static double MMG5_lenSurfEdg_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int np0, MMG5_int np1, int8_t isedg)
int intmet_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int8_t i, MMG5_int ip, double s)
Definition: intmet_s.c:104
int intmet_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int8_t i, MMG5_int ip, double s)
Definition: intmet_s.c:77
int MMG5_gradsiz_iso(MMG5_pMesh mesh, MMG5_pSol met)
Definition: isosiz.c:278
int MMG5_compute_meanMetricAtMarkedPoints_iso(MMG5_pMesh mesh, MMG5_pSol met)
Definition: isosiz.c:167
int MMG5_gradsizreq_iso(MMG5_pMesh mesh, MMG5_pSol met)
Definition: isosiz.c:372
int MMGS_defsiz_iso(MMG5_pMesh mesh, MMG5_pSol met)
Definition: isosiz_s.c:142
LIBMMG_CORE_EXPORT int MMG5_Clean_isoEdges(MMG5_pMesh mesh)
Definition: libtools.c:368
API headers and documentation for the mmgs library.
LIBMMGS_EXPORT int(* MMGS_doSol)(MMG5_pMesh mesh, MMG5_pSol met)
Compute an isotropic size map according to the mean of the length of the edges passing through a vert...
Definition: mmgsexterns.c:9
#define MMGS_LMAX
Definition: libmmgs.h:98
@ MMGS_IPARAM_keepRef
Definition: libmmgs.h:117
@ MMGS_IPARAM_nreg
Definition: libmmgs.h:122
@ MMGS_IPARAM_optim
Definition: libmmgs.h:118
@ MMGS_IPARAM_xreg
Definition: libmmgs.h:123
@ MMGS_DPARAM_hgrad
Definition: libmmgs.h:136
@ MMGS_IPARAM_nomove
Definition: libmmgs.h:121
@ MMGS_IPARAM_renum
Definition: libmmgs.h:128
@ MMGS_IPARAM_numsubdomain
Definition: libmmgs.h:127
@ MMGS_DPARAM_xreg
Definition: libmmgs.h:139
@ MMGS_IPARAM_nosizreq
Definition: libmmgs.h:130
@ MMGS_DPARAM_angleDetection
Definition: libmmgs.h:131
@ MMGS_IPARAM_verbose
Definition: libmmgs.h:110
@ MMGS_IPARAM_angle
Definition: libmmgs.h:113
@ MMGS_IPARAM_isoref
Definition: libmmgs.h:116
@ MMGS_DPARAM_hsiz
Definition: libmmgs.h:134
@ MMGS_IPARAM_debug
Definition: libmmgs.h:112
@ MMGS_IPARAM_noswap
Definition: libmmgs.h:120
@ MMGS_DPARAM_ls
Definition: libmmgs.h:138
@ MMGS_DPARAM_hmin
Definition: libmmgs.h:132
@ MMGS_IPARAM_iso
Definition: libmmgs.h:114
@ MMGS_DPARAM_hausd
Definition: libmmgs.h:135
@ MMGS_IPARAM_mem
Definition: libmmgs.h:111
@ MMGS_DPARAM_rmc
Definition: libmmgs.h:140
@ MMGS_IPARAM_isosurf
Definition: libmmgs.h:115
@ MMGS_DPARAM_hgradreq
Definition: libmmgs.h:137
@ MMGS_DPARAM_hmax
Definition: libmmgs.h:133
@ MMGS_IPARAM_noinsert
Definition: libmmgs.h:119
int movridpt_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *list, int ilist)
Definition: movpt_s.c:595
int movintpt_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *list, int ilist)
Definition: movpt_s.c:52
int MMGS_memOption(MMG5_pMesh mesh)
Definition: zaldy_s.c:205
static int MMGS_solTruncatureForOptim(MMG5_pMesh mesh, MMG5_pSol met, int ani)
int MMGS_defaultValues(MMG5_pMesh mesh)
Print the default parameter values.
int MMGS_Get_adjaVerticesFast(MMG5_pMesh mesh, MMG5_int ip, MMG5_int start, MMG5_int lispoi[MMGS_LMAX])
Find adjacent vertices of a triangle.
void MMGS_destockOptions(MMG5_pMesh mesh, MMG5_Info *info)
Recover the info structure stored in the mesh structure.
int MMGS_stockOptions(MMG5_pMesh mesh, MMG5_Info *info)
Store the info structure in the mesh structure.
static int MMGS_unitTensor_3D(MMG5_pMesh mesh, MMG5_int k, int i, MMG5_pPoint p1, double *m)
int MMGS_usage(char *prog)
Print help for mmgs options.
Definition: libmmgs_tools.c:83
int MMGS_Get_numberOfNonBdyEdges(MMG5_pMesh mesh, MMG5_int *nb_edges)
Get the number of non-boundary edges.
int MMGS_freeLocalPar(MMG5_pMesh mesh)
int MMGS_Get_adjaTri(MMG5_pMesh mesh, MMG5_int kel, MMG5_int listri[3])
Return adjacent triangles of a triangle.
void MMGS_setfunc(MMG5_pMesh mesh, MMG5_pSol met)
Set function pointers for caltet, lenedg, defsiz and gradsiz.
Definition: libmmgs_tools.c:43
static int MMGS_surfopenballRotation(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_int k, int i, int ilist, double r[3][3], double *lispoi, double n[3])
int MMGS_doSol_ani(MMG5_pMesh mesh, MMG5_pSol met)
int MMGS_parsar(int argc, char *argv[], MMG5_pMesh mesh, MMG5_pSol met, MMG5_pSol sol)
Store command line arguments.
int MMGS_doSol_iso(MMG5_pMesh mesh, MMG5_pSol met)
int MMGS_Clean_isoSurf(MMG5_pMesh mesh)
Clean data (triangles and edges) linked to isosurface.
void MMGS_Free_solutions(MMG5_pMesh mesh, MMG5_pSol sol)
Free a solution.
int MMGS_Get_nonBdyEdge(MMG5_pMesh mesh, MMG5_int *e0, MMG5_int *e1, MMG5_int *ref, MMG5_int idx)
Get vertices and reference of a non-boundary edge.
static int MMGS_unitTensor_2D(MMG5_pMesh mesh, MMG5_int k, int i, MMG5_pPoint p1, double *m, double isqhmax)
int MMGS_Compute_eigenv(double m[6], double lambda[3], double vp[3][3])
Compute the real eigenvalues and eigenvectors of a symmetric matrix.
int MMGS_Set_constantSize(MMG5_pMesh mesh, MMG5_pSol met)
Compute a constant size map.
@ MMG5_Tensor
Definition: libmmgtypes.h:221
@ MMG5_Vertex
Definition: libmmgtypes.h:230
void MMG5_advancedUsage(void)
Definition: libtools.c:305
void MMG5_mmgUsage(char *prog)
Definition: libtools.c:212
void MMG5_paramUsage1(void)
Definition: libtools.c:242
void MMG5_mmgDefaultValues(MMG5_pMesh mesh)
Definition: libtools.c:70
void MMG5_paramUsage2(void)
Definition: libtools.c:261
#define MG_REQ
#define MG_GEO
#define MMG5_SAFE_CALLOC(ptr, size, type, law)
int MMG5_3dSolTruncature_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: scalem.c:453
double MMG5_caltri_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria ptt)
Definition: quality.c:115
#define MG_EOK(pt)
#define MMG5_ADD_MEM(mesh, size, message, law)
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
#define MMG5_HMAXCOE
#define MG_SIN(tag)
#define MMG5_UNSET
static const uint8_t MMG5_inxt2[6]
int MMG5_solTruncature_iso(MMG5_pMesh mesh, MMG5_pSol met)
Definition: scalem.c:299
int MMG5_nortri(MMG5_pMesh mesh, MMG5_pTria pt, double *n)
Definition: tools.c:209
#define MG_CRN
int MMG5_rotmatrix(double n[3], double r[3][3])
Definition: tools.c:467
#define MG_NOM
#define MMG5_FILESTR_LGTH
double MMG5_caltri_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria ptt)
Definition: quality.c:199
#define MMG5_EPSD2
#define MG_REF
#define MMG5_SAFE_FREE(ptr)
#define MMG_FSCANF(stream, format,...)
#define MMG5_DEL_MEM(mesh, ptr)
int MMG5_invmat(double *m, double *mi)
Definition: tools.c:562
#define MMG5_SAFE_RECALLOC(ptr, prevSize, newSize, type, message, law)
Structure to store edges of am MMG mesh.
Definition: libmmgtypes.h:311
MMG5_int b
Definition: libmmgtypes.h:312
MMG5_int ref
Definition: libmmgtypes.h:313
MMG5_int a
Definition: libmmgtypes.h:312
Structure to store input parameters of the job.
Definition: libmmgtypes.h:523
int8_t iso
Definition: libmmgtypes.h:541
double hsiz
Definition: libmmgtypes.h:525
int8_t isosurf
Definition: libmmgtypes.h:542
uint8_t ani
Definition: libmmgtypes.h:553
int8_t lag
Definition: libmmgtypes.h:547
MMG5_pPar par
Definition: libmmgtypes.h:524
uint8_t optim
Definition: libmmgtypes.h:553
MMG mesh structure.
Definition: libmmgtypes.h:613
MMG5_int ntmax
Definition: libmmgtypes.h:620
MMG5_Info info
Definition: libmmgtypes.h:659
MMG5_pPoint point
Definition: libmmgtypes.h:649
char * nameout
Definition: libmmgtypes.h:661
MMG5_int mark
Definition: libmmgtypes.h:626
MMG5_int * adja
Definition: libmmgtypes.h:632
MMG5_int npmax
Definition: libmmgtypes.h:620
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:650
MMG5_int namax
Definition: libmmgtypes.h:620
MMG5_int base
Definition: libmmgtypes.h:624
MMG5_int nt
Definition: libmmgtypes.h:620
MMG5_pTria tria
Definition: libmmgtypes.h:655
MMG5_int np
Definition: libmmgtypes.h:620
MMG5_pEdge edge
Definition: libmmgtypes.h:657
MMG5_int na
Definition: libmmgtypes.h:620
char * namein
Definition: libmmgtypes.h:660
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 xp
Definition: libmmgtypes.h:285
MMG5_int flag
Definition: libmmgtypes.h:288
char * nameout
Definition: libmmgtypes.h:683
char * namein
Definition: libmmgtypes.h:682
double * m
Definition: libmmgtypes.h:680
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
double n2[3]
Definition: libmmgtypes.h:301
double n1[3]
Definition: libmmgtypes.h:301