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 int i;
129 char namein[MMG5_FILESTR_LGTH];
130
131 /* First step: search if user want to see the default parameters values. */
132 for ( i=1; i< argc; ++i ) {
133 if ( !strcmp(argv[i],"-val") ) {
135 return 0;
136 }
137 }
138
139 /* Second step: read all other arguments. */
140 i = 1;
141 while ( i < argc ) {
142 if ( *argv[i] == '-' ) {
143 switch(argv[i][1]) {
144 case '?':
145 MMGS_usage(argv[0]);
146 return 0;
147 break;
148 case 'a': /* ridge angle */
149 if ( !strcmp(argv[i],"-ar") && ++i < argc ) {
151 atof(argv[i])) )
152 return 0;
153 }
154 break;
155 case 'A': /* anisotropy */
157 return 0;
158 break;
159 case 'h':
160 if ( !strcmp(argv[i],"-hmin") && ++i < argc ) {
162 atof(argv[i])) )
163 return 0;
164 }
165 else if ( !strcmp(argv[i],"-hmax") && ++i < argc ) {
167 atof(argv[i])) )
168 return 0;
169 }
170 else if ( !strcmp(argv[i],"-hsiz") && ++i < argc ) {
172 atof(argv[i])) )
173 return 0;
174
175 }
176 else if ( !strcmp(argv[i],"-hausd") && ++i <= argc ) {
178 atof(argv[i])) )
179 return 0;
180 }
181 else if ( !strcmp(argv[i],"-hgradreq") && ++i <= argc ) {
183 atof(argv[i])) )
184 return 0;
185 }
186 else if ( !strcmp(argv[i],"-hgrad") && ++i <= argc ) {
188 atof(argv[i])) )
189 return 0;
190 }
191 else {
192 MMGS_usage(argv[0]);
193 return 0;
194 }
195 break;
196 case 'd':
197 if ( !strcmp(argv[i],"-default") ) {
198 mesh->mark=1;
199 }
200 else {
202 return 0;
203 }
204 break;
205 case 'i':
206 if ( !strcmp(argv[i],"-in") ) {
207 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-') {
208 if ( !MMGS_Set_inputMeshName(mesh, argv[i]) )
209 return 0;
210
212 return 0;
213 }else{
214 fprintf(stderr,"Missing filname for %c%c\n",argv[i-1][1],argv[i-1][2]);
215 MMGS_usage(argv[0]);
216 return 0;
217 }
218 }
219 else if ( !strcmp(argv[i],"-isoref") && ++i <= argc ) {
221 atoi(argv[i])) )
222 return 0;
223 }
224 else {
225 MMGS_usage(argv[0]);
226 return 0;
227 }
228 break;
229 case 'k':
230 if ( !strcmp(argv[i],"-keep-ref") ) {
232 return 0;
233 }
234 break;
235 case 'l':
236 if ( !strcmp(argv[i],"-ls") ) {
238 return 0;
239 if ( ++i < argc && (isdigit(argv[i][0]) ||
240 (argv[i][0]=='-' && isdigit(argv[i][1])) ) ) {
241 if ( !MMGS_Set_dparameter(mesh,met,MMGS_DPARAM_ls,atof(argv[i])) )
242 return 0;
243 }
244 else i--;
245 }
246 else if ( !strcmp(argv[i],"-lssurf") ) {
248 return 0;
249 if ( ++i < argc && (isdigit(argv[i][0]) ||
250 (argv[i][0]=='-' && isdigit(argv[i][1])) ) ) {
251 if ( !MMGS_Set_dparameter(mesh,met,MMGS_DPARAM_ls,atof(argv[i])) )
252 return 0;
253 }
254 else i--;
255 }
256 break;
257 case 'm':
258 if ( !strcmp(argv[i],"-met") ) {
259 if ( !met ) {
260 fprintf(stderr,"No metric structure allocated for %c%c%c option\n",
261 argv[i-1][1],argv[i-1][2],argv[i-1][3]);
262 return 0;
263 }
264 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-' ) {
265 if ( !MMGS_Set_inputSolName(mesh,met,argv[i]) )
266 return 0;
267 }
268 else {
269 fprintf(stderr,"Missing filname for %c%c%c\n",argv[i-1][1],argv[i-1][2],argv[i-1][3]);
270 MMGS_usage(argv[0]);
271 return 0;
272 }
273 }
274 else if (!strcmp(argv[i],"-m") ) {
275 if ( ++i < argc && isdigit(argv[i][0]) ) {
276 if ( !MMGS_Set_iparameter(mesh,met,MMGS_IPARAM_mem,atoi(argv[i])) )
277 return 0;
278 }
279 else {
280 fprintf(stderr,"Missing argument option %c\n",argv[i-1][1]);
281 MMGS_usage(argv[0]);
282 return 0;
283 }
284 }
285 break;
286 case 'n':
287 if ( !strcmp(argv[i],"-nr") ) {
289 return 0;
290 }
291 else if ( !strcmp(argv[i],"-nsd") ) {
292 if ( ++i < argc && isdigit(argv[i][0]) ) {
293 if ( !MMGS_Set_iparameter(mesh,met,MMGS_IPARAM_numsubdomain,atoi(argv[i])) )
294 return 0;
295 }
296 else {
297 fprintf(stderr,"Missing argument option %c\n",argv[i-1][1]);
298 MMGS_usage(argv[0]);
299 return 0;
300 }
301 }
302 else if ( !strcmp(argv[i],"-noswap") ) {
304 return 0;
305 }
306 else if( !strcmp(argv[i],"-noinsert") ) {
308 return 0;
309 }
310 else if( !strcmp(argv[i],"-nomove") ) {
312 return 0;
313 }
314 else if ( !strcmp(argv[i],"-nreg") ) {
316 return 0;
317 }
318 else if( !strcmp(argv[i],"-nosizreq") ) {
320 return 0;
321 }
322 }
323 break;
324 case 'o':
325 if ( (!strcmp(argv[i],"-out")) || (!strcmp(argv[i],"-o")) ) {
326 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-') {
327 if ( !MMGS_Set_outputMeshName(mesh,argv[i]) )
328 return 0;
329 }else{
330 fprintf(stderr,"Missing filname for %c%c%c\n",
331 argv[i-1][1],argv[i-1][2],argv[i-1][3]);
332 MMGS_usage(argv[0]);
333 return 0;
334 }
335 }
336 else if( !strcmp(argv[i],"-optim") ) {
338 return 0;
339 }
340 else {
341 fprintf(stderr,"Unrecognized option %s\n",argv[i]);
342 MMGS_usage(argv[0]);
343 return 0;
344 }
345 break;
346 case 'r':
347 if ( !strcmp(argv[i],"-rmc") ) {
349 return 0;
350 if ( ++i < argc && (isdigit(argv[i][0]) ) ) {
351 if ( !MMGS_Set_dparameter(mesh,met,MMGS_DPARAM_rmc,atof(argv[i])) )
352 return 0;
353 }
354 else i--;
355 }
356#ifdef USE_SCOTCH
357 else if ( !strcmp(argv[i],"-rn") ) {
358 if ( ++i < argc ) {
359 if ( isdigit(argv[i][0]) ) {
360 if ( !MMGS_Set_iparameter(mesh,met,MMGS_IPARAM_renum,atoi(argv[i])) )
361 return 0;
362 }
363 else {
364 fprintf(stderr,"Missing argument option %s\n",argv[i-1]);
365 MMGS_usage(argv[0]);
366 return 0;
367 }
368 }
369 else {
370 fprintf(stderr,"Missing argument option %s\n",argv[i-1]);
371 MMGS_usage(argv[0]);
372 return 0;
373 }
374 }
375#endif
376 else {
377 fprintf(stderr,"Unrecognized option %s\n",argv[i]);
378 MMGS_usage(argv[0]);
379 return 0;
380 }
381 break;
382 case 's':
383 if ( !strcmp(argv[i],"-sol") ) {
384 /* For retrocompatibility, store the metric if no sol structure available */
385 tmp = sol ? sol : met;
386 assert(tmp);
387 if ( ++i < argc && isascii(argv[i][0]) && argv[i][0]!='-' ) {
388 if ( !MMGS_Set_inputSolName(mesh,tmp,argv[i]) )
389 return 0;
390 }
391 else {
392 fprintf(stderr,"Missing filname for %c%c%c\n",argv[i-1][1],argv[i-1][2],argv[i-1][3]);
393 MMGS_usage(argv[0]);
394 return 0;
395 }
396 }
397 break;
398 case 'v':
399 if ( ++i < argc ) {
400 if ( argv[i][0] == '-' || isdigit(argv[i][0]) ) {
401 if ( !MMGS_Set_iparameter(mesh,met,MMGS_IPARAM_verbose,atoi(argv[i])) )
402 return 0;
403 }
404 else
405 i--;
406 }
407 else {
408 fprintf(stderr,"Missing argument option %c\n",argv[i-1][1]);
409 MMGS_usage(argv[0]);
410 return 0;
411 }
412 break;
413 case 'x':
414 if ( !strcmp(argv[i],"-xreg") ) {
416 return 0;
417 }
418 break;
419 default:
420 fprintf(stderr,"Unrecognized option %s\n",argv[i]);
421 MMGS_usage(argv[0]);
422 return 0;
423 }
424 }
425 else {
426 if ( mesh->namein == NULL ) {
427 if ( !MMGS_Set_inputMeshName(mesh,argv[i]) )
428 return 0;
429 if ( mesh->info.imprim == -99 ) {
431 return 0;
432 }
433 }
434 else if ( mesh->nameout == NULL ) {
435 if ( !MMGS_Set_outputMeshName(mesh,argv[i]) )
436 return 0;
437 }
438 else {
439 fprintf(stdout,"Argument %s ignored\n",argv[i]);
440 MMGS_usage(argv[0]);
441 return 0;
442 }
443 }
444 i++;
445 }
446
447 /* check file names */
448 if ( mesh->info.imprim == -99 ) {
449 fprintf(stdout,"\n -- PRINT (0 10(advised) -10) ?\n");
450 fflush(stdin);
451 MMG_FSCANF(stdin,"%d",&i);
453 return 0;
454 }
455
456 if ( mesh->namein == NULL ) {
457 fprintf(stdout," -- INPUT MESH NAME ?\n");
458 fflush(stdin);
459 MMG_FSCANF(stdin,"%127s",namein);
460 if ( !MMGS_Set_inputMeshName(mesh,namein) )
461 return 0;
462 }
463
464 if ( mesh->nameout == NULL ) {
465 if ( !MMGS_Set_outputMeshName(mesh,"") )
466 return 0;
467 }
468
469 /* adp mode: if the metric name has been stored in sol, move it in met */
470 if ( met->namein==NULL && sol && sol->namein &&
471 !(mesh->info.iso || mesh->info.isosurf || mesh->info.lag>=0) ) {
473 return 0;
475 }
476
477 /* default : store solution name in iso mode, metric name otherwise */
478 tmp = ( mesh->info.iso || mesh->info.isosurf || mesh->info.lag >=0 ) ? sol : met;
479 assert ( tmp );
480 if ( tmp->namein == NULL ) {
481 if ( !MMGS_Set_inputSolName(mesh,tmp,"") ) { return 0; }
482 }
483 if ( met->nameout == NULL ) {
484 if ( !MMGS_Set_outputSolName(mesh,met,"") )
485 return 0;
486 }
487 return 1;
488}
489
491
492 free(mesh->info.par);
493 mesh->info.npar = 0;
494
495 return 1;
496}
497
499
500 memcpy(&mesh->info,info,sizeof(MMG5_Info));
502 if( mesh->info.mem > 0) {
503 if ( mesh->npmax < mesh->np || mesh->ntmax < mesh->nt ) {
504 return 0;
505 } else if(mesh->info.mem < 39)
506 return 0;
507 }
508 return 1;
509}
510
512
513 memcpy(info,&mesh->info,sizeof(MMG5_Info));
514 return;
515}
516
518 MMG5_pTria pt,pt1;
519 MMG5_pEdge ped;
520 MMG5_int *adja,k,j,iel;
521 int i,i1,i2;
522
523 *nb_edges = 0;
524 if ( mesh->tria ) {
525 /* Create the triangle adjacency if needed */
526 if ( !mesh->adja ) {
527 if ( !MMGS_hashTria(mesh) ) {
528 fprintf(stderr,"\n ## Error: %s: unable to create "
529 "adjacency table.\n",__func__);
530 return 0;
531 }
532 }
533
534 /* Count the number of non boundary edges */
535 for ( k=1; k<=mesh->nt; k++ ) {
536 pt = &mesh->tria[k];
537 if ( !MG_EOK(pt) ) continue;
538
539 adja = &mesh->adja[3*(k-1)+1];
540
541 for ( i=0; i<3; i++ ) {
542 /* Do not treat boundary edges */
543 if ( MG_EDG(pt->tag[i]) ) continue;
544
545 iel = adja[i] / 3;
546 assert ( iel != k );
547
548 pt1 = &mesh->tria[iel];
549
550 if ( (!iel) || (pt->ref != pt1->ref) ) {
551 /* Do not treat boundary edges */
552 continue;
553 }
554 if ( k < iel ) {
555 /* Treat edge from the triangle with lowest index */
556 ++(*nb_edges);
557 }
558 }
559 }
560
561 /* Append the non boundary edges to the boundary edges array */
562 if ( mesh->na ) {
563 MMG5_ADD_MEM(mesh,(*nb_edges)*sizeof(MMG5_Edge),"non boundary edges",
564 printf(" Exit program.\n");
565 return 0);
566 MMG5_SAFE_RECALLOC(mesh->edge,(mesh->na+1),(mesh->na+(*nb_edges)+1),
567 MMG5_Edge,"non bdy edges arrray",return 0);
568 }
569 else {
570 MMG5_ADD_MEM(mesh,((*nb_edges)+1)*sizeof(MMG5_Edge),"non boundary edges",
571 printf(" Exit program.\n");
572 return 0);
573 MMG5_SAFE_RECALLOC(mesh->edge,0,(*nb_edges)+1,
574 MMG5_Edge,"non bdy edges arrray",return 0);
575 }
576
577 j = mesh->na+1;
578 for ( k=1; k<=mesh->nt; k++ ) {
579 pt = &mesh->tria[k];
580 if ( !MG_EOK(pt) ) continue;
581
582 adja = &mesh->adja[3*(k-1)+1];
583
584 for ( i=0; i<3; i++ ) {
585 /* Do not treat boundary edges */
586 if ( MG_EDG(pt->tag[i]) ) continue;
587
588 i1 = MMG5_inxt2[i];
589 i2 = MMG5_iprv2[i];
590 iel = adja[i] / 3;
591 assert ( iel != k );
592
593 pt1 = &mesh->tria[iel];
594
595 if ( (!iel) || (pt->ref != pt1->ref) ) {
596 /* Do not treat boundary edges */
597 continue;
598 }
599 if ( k < iel ) {
600 /* Treat edge from the triangle with lowest index */
601 ped = &mesh->edge[j++];
602 assert ( ped );
603 ped->a = pt->v[i1];
604 ped->b = pt->v[i2];
605 ped->ref = pt->edg[i];
606 }
607 }
608 }
609 }
610 return 1;
611}
612
613int MMGS_Get_nonBdyEdge(MMG5_pMesh mesh, MMG5_int* e0, MMG5_int* e1, MMG5_int* ref, MMG5_int idx) {
614 MMG5_pEdge ped;
615 size_t na_tot=0;
616 char *ptr_c = (char*)mesh->edge;
617
618 if ( !mesh->edge ) {
619 fprintf(stderr,"\n ## Error: %s: edge array is not allocated.\n"
620 " Please, call the MMGS_Get_numberOfNonBdyEdges function"
621 " before the %s one.\n",
622 __func__,__func__);
623 return 0;
624 }
625
626 ptr_c = ptr_c-sizeof(size_t);
627 na_tot = *((size_t*)ptr_c);
628
629 if ( (size_t)mesh->namax==na_tot ) {
630 fprintf(stderr,"\n ## Error: %s: no internal edge.\n"
631 " Please, call the MMGS_Get_numberOfNonBdyEdges function"
632 " before the %s one and check that the number of internal"
633 " edges is non null.\n",
634 __func__,__func__);
635 }
636
637 if ( (size_t)mesh->namax+idx > na_tot ) {
638 fprintf(stderr,"\n ## Error: %s: Can't get the internal edge of index %" MMG5_PRId "."
639 " Index must be between 1 and %zu.\n",
640 __func__,idx,na_tot-(size_t)mesh->namax);
641 }
642
643 ped = &mesh->edge[mesh->na+idx];
644
645 *e0 = ped->a;
646 *e1 = ped->b;
647
648 if ( ref != NULL ) {
649 *ref = mesh->edge[mesh->na+idx].ref;
650 }
651
652 return 1;
653}
654
655int MMGS_Get_adjaTri(MMG5_pMesh mesh, MMG5_int kel, MMG5_int listri[3]) {
656
657 if ( ! mesh->adja ) {
658 if (! MMGS_hashTria(mesh))
659 return 0;
660 }
661
662 listri[0] = mesh->adja[3*(kel-1)+1]/3;
663 listri[1] = mesh->adja[3*(kel-1)+2]/3;
664 listri[2] = mesh->adja[3*(kel-1)+3]/3;
665
666 return 1;
667}
668
669int MMGS_Get_adjaVerticesFast(MMG5_pMesh mesh, MMG5_int ip,MMG5_int start, MMG5_int lispoi[MMGS_LMAX])
670{
671 MMG5_pTria pt;
672 MMG5_int k,prevk,*adja;
673 int i,i1,i2,iploc,nbpoi;
674
675 pt = &mesh->tria[start];
676
677 for ( iploc=0; iploc<3; ++iploc ) {
678 if ( pt->v[iploc] == ip ) break;
679 }
680
681 assert(iploc!=3);
682
683 k = start;
684 i = iploc;
685 nbpoi = 0;
686 do {
687 if ( nbpoi == MMGS_LMAX ) {
688 fprintf(stderr,"\n ## Warning: %s: unable to compute adjacent"
689 " vertices of the vertex %" MMG5_PRId ":\nthe ball of point contain too many"
690 " elements.\n",__func__,ip);
691 return 0;
692 }
693 i1 = MMG5_inxt2[i];
694 lispoi[nbpoi] = mesh->tria[k].v[i1];
695 ++nbpoi;
696
697 adja = &mesh->adja[3*(k-1)+1];
698 prevk = k;
699 k = adja[i1] / 3;
700 i = adja[i1] % 3;
701 i = MMG5_inxt2[i];
702 }
703 while ( k && k != start );
704
705 if ( k > 0 ) return nbpoi;
706
707 /* store the last point of the boundary triangle */
708 if ( nbpoi == MMGS_LMAX ) {
709 fprintf(stderr,"\n ## Warning: %s: unable to compute adjacent vertices of the"
710 " vertex %" MMG5_PRId ":\nthe ball of point contain too many elements.\n",
711 __func__,ip);
712 return 0;
713 }
714 i1 = MMG5_inxt2[i1];
715 lispoi[nbpoi] = mesh->tria[prevk].v[i1];
716 ++nbpoi;
717
718 /* check if boundary hit */
719 k = start;
720 i = iploc;
721 do {
722 adja = &mesh->adja[3*(k-1)+1];
723 i2 = MMG5_iprv2[i];
724 k = adja[i2] / 3;
725 if ( k == 0 ) break;
726
727 if ( nbpoi == MMGS_LMAX ) {
728 fprintf(stderr,"\n ## Warning: %s: unable to compute adjacent vertices of the"
729 " vertex %" MMG5_PRId ":\nthe ball of point contain too many elements.\n",
730 __func__,ip);
731 return 0;
732 }
733 i = adja[i2] % 3;
734 lispoi[nbpoi] = mesh->tria[k].v[i];
735 ++nbpoi;
736
737 i = MMG5_iprv2[i];
738 }
739 while ( k );
740
741 return nbpoi;
742}
743
755static inline
757 MMG5_int k;
758 int i,ier;
759
760 assert ( mesh->info.optim );
761
762 /* Detect points not used by the mesh */
763 ++mesh->base;
764
765#ifndef NDEBUG
766 for (k=1; k<=mesh->np; k++) {
767 assert ( mesh->point[k].flag < mesh->base );
768 }
769#endif
770
771 for (k=1; k<=mesh->nt; k++) {
772 MMG5_pTria ptt = &mesh->tria[k];
773 if ( !MG_EOK(ptt) ) continue;
774
775 for (i=0; i<3; i++) {
776 mesh->point[ptt->v[i]].flag = mesh->base;
777 }
778 }
779
780 /* Compute hmin/hmax on unflagged points and truncate the metric */
781 if ( !ani ) {
783 }
784 else {
785 MMG5_solTruncature_ani = MMG5_3dSolTruncature_ani;
787 }
788
789 return ier;
790}
791
792
806 MMG5_pTria ptt;
807 MMG5_pPoint p1,p2;
808 double ux,uy,uz,dd;
809 MMG5_int k,ipa,ipb;
810 int i,type;
811 //We guess that we have less than INT32_MAX edges
812 // passing through each point
813 int *mark;
814
815 MMG5_SAFE_CALLOC(mark,mesh->np+1,int,return 0);
816
817 /* Memory alloc */
818 if ( met->size!=1 ) {
819 fprintf(stderr,"\n ## Error: %s: unexpected size of metric: %d.\n",
820 __func__,met->size);
821 return 0;
822 }
823
824 type = 1;
825 if ( !MMGS_Set_solSize(mesh,met,MMG5_Vertex,mesh->np,type) )
826 return 0;
827
828 /* Travel the triangles edges and add the edge contribution to edges
829 * extermities */
830 for (k=1; k<=mesh->nt; k++) {
831 ptt = &mesh->tria[k];
832 if ( !MG_EOK(ptt) ) continue;
833
834 for (i=0; i<3; i++) {
835 ipa = ptt->v[i];
836 ipb = ptt->v[MMG5_inxt2[i]];
837 p1 = &mesh->point[ipa];
838 p2 = &mesh->point[ipb];
839
840 ux = p1->c[0] - p2->c[0];
841 uy = p1->c[1] - p2->c[1];
842 uz = p1->c[2] - p2->c[2];
843 dd = sqrt(ux*ux + uy*uy + uz*uz);
844
845 met->m[ipa] += dd;
846 mark[ipa]++;
847 met->m[ipb] += dd;
848 mark[ipb]++;
849 }
850 }
851
852 /* vertex size */
853 for (k=1; k<=mesh->np; k++) {
854 if ( !mark[k] ) {
855 continue;
856 }
857 else
858 met->m[k] = met->m[k] / (double)mark[k];
859 }
860
861 MMG5_SAFE_FREE(mark);
862
864
865 return 1;
866}
867
884static inline
885int MMGS_unitTensor_3D( MMG5_pMesh mesh,MMG5_int k,int i,MMG5_pPoint p1,double *m) {
886 MMG5_int list[MMGS_LMAX+2];
887 int ilist,j;
888 int8_t open;
889
891 ilist = MMG5_boulet(mesh,k,i,list,1,&open);
892 if ( ilist < 1 ) {
893 fprintf(stderr,"\n ## Error: %s: unable to compute ball of point.\n",
894 __func__);
895 return 0;
896 }
897
899 if ( (!MG_SIN(p1->tag)) && (MG_GEO & p1->tag) && open ) {
900 /* MG_GEO point along an open boundary: we want to compute the 2D unit
901 * tensor */
902 return 0;
903 }
904
905 for ( j=0; j<6; ++j ) {
906 m[j] = 0.;
907 }
908
909 for ( j=0; j<ilist; ++j ) {
910 /* Compute euclidean edge length */
911 double u[3];
912 MMG5_int iel = list[j] / 3;
913 int8_t i1 = list[j] % 3;
914 int8_t i2 = MMG5_inxt2[i1];
915
916 MMG5_pTria ptt = &mesh->tria[iel];
917 MMG5_pPoint p2 = &mesh->point[ptt->v[i2]];
918
919 u[0] = p1->c[0] - p2->c[0];
920 u[1] = p1->c[1] - p2->c[1];
921 u[2] = p1->c[2] - p2->c[2];
922
923 m[0] += u[0]*u[0];
924 m[1] += u[0]*u[1];
925 m[2] += u[0]*u[2];
926 m[3] += u[1]*u[1];
927 m[4] += u[1]*u[2];
928 m[5] += u[2]*u[2];
929 }
930
931 double tensordot[6];
932 int ier = MMG5_invmat(m,tensordot);
933
934 /* Invmat make the assumtion that input matrix is invertible (always the case
935 * normally). Here, if all edges belongs to the same plane, it is not the case
936 * so we have to check the values of the resulting matrix even if invmat
937 * succeed */
938 if ( ier ) {
939 for ( j=0; j<6; ++j ) {
940 if ( !isfinite(tensordot[j]) ) {
941 ier = 0;
942 break;
943 }
944 }
945 }
946
947 if ( ier ) {
948 double lambda[3],vp[3][3];
949 if ( !MMG5_eigenv3d(1,tensordot,lambda,vp) ) {
950 ier = 0;
951 }
952 else if ( (!isfinite(lambda[0])) || (!isfinite(lambda[1])) || (!isfinite(lambda[2])) ) {
953 ier = 0;
954 }
955 else if ( lambda[0]<=0 || lambda[1]<=0 || lambda[2]<=0 ) {
956 ier = 0;
957 }
958 }
959
960 /* Non invertible matrix: put FLT_MIN waiting for a treatment later */
961 if ( !ier ) {
962 m[0] = FLT_MIN;
963 m[1] = 0;
964 m[2] = 0;
965 m[3] = FLT_MIN;
966 m[4] = 0;
967 m[5] = FLT_MIN;
968 return 0;
969 }
970
971 double dd = (double)ilist/3.;
972 for ( j=0; j<6; ++j ) {
973 m[j] = dd*tensordot[j];
974 }
975
976 return 1;
977}
978
995static inline
997 int ilist,double r[3][3],double *lispoi,double n[3]) {
998 MMG5_pTria ptt;
999 MMG5_pPoint p2;
1000 double ux,uy,uz;
1001 MMG5_int *adja,kold;
1002 int jold,i1;
1003
1004 if ( !MMG5_rotmatrix(n,r) ) {
1005 return 0;
1006 }
1007
1008 /* Enumeration of the ball starting from a boundary */
1009 MMG5_int iel = k;
1010 int j = i;
1011 do {
1012 adja = &mesh->adja[3*(iel-1)+1];
1013 i1 = MMG5_iprv2[j];
1014 kold = iel;
1015 jold = j;
1016 iel = adja[i1] / 3;
1017 j = (int)adja[i1] % 3;
1018 j = MMG5_iprv2[j];
1019 }
1020 // Remark: here the test k!=start is a security bound: theorically it is
1021 // useless but in case of bad edge tag, it ensure that the loop is not
1022 // infinite.
1023 while ( iel && iel != k );
1024
1025 iel = kold;
1026 j = jold;
1027 int idx = 0;
1028 do {
1029 ptt = &mesh->tria[iel];
1030 // here, p1 == &mesh->point[ptt->v[j]]
1031
1032 adja = &mesh->adja[3*(iel-1)+1];
1033 i1 = MMG5_inxt2[j];
1034 p2 = &mesh->point[ptt->v[i1]];
1035
1036 ux = p2->c[0] - p0->c[0];
1037 uy = p2->c[1] - p0->c[1];
1038 uz = p2->c[2] - p0->c[2];
1039
1040 lispoi[3*idx+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
1041 lispoi[3*idx+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
1042 lispoi[3*idx+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
1043
1044 iel = adja[i1] / 3;
1045 j = (int)adja[i1] % 3;
1046 j = MMG5_inxt2[j];
1047
1048 ++idx;
1049 }
1050 while ( iel );
1051
1052 /* last point : the half-ball is open : ilist tria, and ilist +1 points ;
1053 lists are enumerated in direct order */
1054 i1 = MMG5_inxt2[i1];
1055 p2 = &mesh->point[ptt->v[i1]];
1056
1057 ux = p2->c[0] - p0->c[0];
1058 uy = p2->c[1] - p0->c[1];
1059 uz = p2->c[2] - p0->c[2];
1060
1061 lispoi[3*idx+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
1062 lispoi[3*idx+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
1063 lispoi[3*idx+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
1064
1065 assert ( idx == ilist );
1066
1067 /* Check all projections over tangent plane. */
1068 for (j=0; j<ilist; j++) {
1069 double area = lispoi[3*j+1]*lispoi[3*(j+1)+2] - lispoi[3*j+2]*lispoi[3*(j+1)+1];
1070 if ( area <= 0.0 ) {
1071 fprintf(stderr,"\n ## Error: %s: unable to compute ball rotation.\n",
1072 __func__);
1073 return 0;
1074 }
1075 }
1076 return 1;
1077}
1078
1093static inline
1095 double *m,double isqhmax) {
1096 MMG5_pTria ptt;
1097 double r[3][3],lispoi[3*MMGS_LMAX+1],b0[3],b1[3],b2[3],dd;
1098 MMG5_int list[MMGS_LMAX+2];
1099 int ilist,j;
1100 int8_t opn;
1101
1104 /* Possible improvement: if we have called MMGS_unitTensor_3D previously,
1105 * boulet is already computed */
1106 ilist = MMG5_boulet(mesh,k,i,list,1,&opn);
1107 if ( ilist < 1 ) {
1108 fprintf(stderr,"\n ## Error: %s: unable to compute ball of point.\n",
1109 __func__);
1110 return 0;
1111 }
1112
1113
1116 /* If point \a p1 is corner or required we compute the normal
1117 at point as the * mean of the normals at triangles of the ball. If the point
1118 is ridge (can be * non-manifold), we compute it as the mean of n1 and n2. In
1119 the other cases, * the normal is stored in p1->n */
1120 double nn[3] = {0.,0.,0.};
1121 if ( MG_SIN(p1->tag) ) {
1122 /* Corner or required point: compute the normal at point as the mean of
1123 * normals at triangles */
1124 for ( j=0; j<ilist; ++j ) {
1125 ptt = &mesh->tria[list[j]/3];
1126 double n[3];
1127
1128 MMG5_nortri(mesh,ptt,n);
1129 nn[0] += n[0]; nn[1] += n[1]; nn[2] += n[2];
1130 }
1131 /* normalization */
1132 dd = nn[0]*nn[0] + nn[1]*nn[1] + nn[2]*nn[2];
1133 if ( dd > MMG5_EPSD2 ) {
1134 dd = 1.0 / sqrt(dd);
1135 nn[0] *= dd;
1136 nn[1] *= dd;
1137 nn[2] *= dd;
1138 }
1139 }
1140 else if ( MG_GEO & p1->tag ) {
1141 if ( MG_NOM & p1->tag ) {
1142 fprintf(stderr,"\n ## Error: %s: we should not pass here with a "
1143 "non-manifold point: it sould always be posible to compute the 3D"
1144 " unit tensor on such points.\n",
1145 __func__);
1146 return 0;
1147 }
1148 /* Manifold ridge point: compute the normal as the mean of the 2 computed
1149 * normals */
1150 assert ( p1->xp );
1151 nn[0] = mesh->xpoint[p1->xp].n1[0] + mesh->xpoint[p1->xp].n2[0];
1152 nn[1] = mesh->xpoint[p1->xp].n1[1] + mesh->xpoint[p1->xp].n2[1];
1153 nn[2] = mesh->xpoint[p1->xp].n1[2] + mesh->xpoint[p1->xp].n2[2];
1154
1155 /* normalization */
1156 dd = nn[0]*nn[0] + nn[1]*nn[1] + nn[2]*nn[2];
1157 if ( dd > MMG5_EPSD2 ) {
1158 dd = 1.0 / sqrt(dd);
1159 nn[0] *= dd;
1160 nn[1] *= dd;
1161 nn[2] *= dd;
1162 }
1163 }
1164 else if ( MG_REF & p1->tag ) {
1165 /* Reference point: normal is stored in the xpoint */
1166 assert ( p1->xp );
1167 nn[0] = mesh->xpoint[p1->xp].n1[0];
1168 nn[1] = mesh->xpoint[p1->xp].n1[1];
1169 nn[2] = mesh->xpoint[p1->xp].n1[2];
1170 }
1171 else {
1172 /* Regular point: normal is stored in the field n of the point */
1173 nn[0] = p1->n[0]; nn[1] = p1->n[1]; nn[2] = p1->n[2];
1174 }
1175
1178 if ( opn ) {
1179 if ( !MMGS_surfopenballRotation(mesh,p1,k,i,ilist,r,lispoi,nn) ) {
1180 fprintf(stderr,"\n ## Error: %s: unable to compute opened ball rotation.\n",
1181 __func__);
1182 return 0;
1183 }
1184 }
1185 else {
1186 if ( !MMGS_surfballRotation(mesh,p1,list,ilist,r,lispoi,nn) ) {
1187 fprintf(stderr,"\n ## Error: %s: unable to compute ball rotation.\n",
1188 __func__);
1189 return 0;
1190 }
1191 }
1192
1194 double tensordot[3];
1195 tensordot[0] = 0.;
1196 tensordot[1] = 0.;
1197 tensordot[2] = 0.;
1198
1199 for ( j=0; j<ilist; ++j ) {
1200 /* Compute the 2D metric tensor from the projection of the vectors on
1201 * the tangent plane */
1202 tensordot[0] += lispoi[3*j+1]*lispoi[3*j+1];
1203 tensordot[1] += lispoi[3*j+1]*lispoi[3*j+2];
1204 tensordot[2] += lispoi[3*j+2]*lispoi[3*j+2];
1205 }
1206
1207 /* Metric = nedges/dim * inv (sum(tensor_dot(edges,edges))) */
1208 dd = 1./(tensordot[0]*tensordot[2] - tensordot[1]*tensordot[1]);
1209 dd *= (double)ilist/2.;
1210
1211 double tmp = tensordot[0];
1212
1213 tensordot[0] = dd*tensordot[2];
1214 tensordot[1] = -dd*tensordot[1];
1215 tensordot[2] = dd*tmp;
1216
1217#ifndef NDEBUG
1218 /* Check 2D metric */
1219 double lambda[2],vp[2][2];
1220 MMG5_eigensym(tensordot,lambda,vp);
1221
1222 assert (lambda[0] > 0. && lambda[1] > 0. && "Negative eigenvalue");
1223
1224 /* Normally the case where the point belongs to only 2 colinear points is
1225 impossible */
1226 assert (isfinite(lambda[0]) && isfinite(lambda[1]) && "wrong eigenvalue");
1227#endif
1228
1229 /* At this point, tensordot (with 0 replaced by isqhmax in the z
1230 direction) is the desired metric, except it is expressed in the rotated
1231 canonical basis, that is tensordot = R * metric in cb * ^t R, so metric
1232 in cb = ^tR*intm*R */
1233 // intm = intm[0] intm[1] 0
1234 // intm[1] intm[2] 0
1235 // 0 0 isqhmax
1236
1237 /* b0 and b1 serve now for nothing : let them be the lines of matrix intm*R */
1238
1239 // Remark: here, we put a 'fake' value along the normal direction but we can't
1240 // use a nan or inf value because it impacts the computation of the rotation
1241 // for the other directions
1242 b0[0] = tensordot[0]*r[0][0] + tensordot[1]*r[1][0];
1243 b0[1] = tensordot[0]*r[0][1] + tensordot[1]*r[1][1];
1244 b0[2] = tensordot[0]*r[0][2] + tensordot[1]*r[1][2];
1245 b1[0] = tensordot[1]*r[0][0] + tensordot[2]*r[1][0];
1246 b1[1] = tensordot[1]*r[0][1] + tensordot[2]*r[1][1];
1247 b1[2] = tensordot[1]*r[0][2] + tensordot[2]*r[1][2];
1248
1249 b2[0] = isqhmax*r[2][0];
1250 b2[1] = isqhmax*r[2][1];
1251 b2[2] = isqhmax*r[2][2];
1252
1253 m[0] = r[0][0] * b0[0] + r[1][0] * b1[0] + r[2][0] * b2[0];
1254 m[1] = r[0][0] * b0[1] + r[1][0] * b1[1] + r[2][0] * b2[1];
1255 m[2] = r[0][0] * b0[2] + r[1][0] * b1[2] + r[2][0] * b2[2];
1256
1257 m[3] = r[0][1] * b0[1] + r[1][1] * b1[1] + r[2][1] * b2[1];
1258 m[4] = r[0][1] * b0[2] + r[1][1] * b1[2] + r[2][1] * b2[2];
1259
1260 m[5] = r[0][2] * b0[2] + r[1][2] * b1[2] + r[2][2] * b2[2];
1261
1262 return 1;
1263}
1264
1265
1266
1281 MMG5_pTria ptt;
1282 MMG5_pPoint p1;
1283 double *m,tensordot[6];
1284 MMG5_int k,iadr,ip;
1285 int i,j,type;
1286
1287 /* Memory alloc */
1288 if ( met->size!=6 ) {
1289 fprintf(stderr,"\n ## Error: %s: unexpected size of metric: %d.\n",
1290 __func__,met->size);
1291 return 0;
1292 }
1293
1294 type = 3;
1295 if ( !MMGS_Set_solSize(mesh,met,MMG5_Vertex,mesh->np,type) ) {
1296 fprintf(stderr,"\n ## Error: %s: unable to allocate metric.\n",
1297 __func__);
1298 return 0;
1299 }
1300
1302 ++mesh->base;
1303
1304#ifndef NDEBUG
1305 for (k=1; k<=mesh->np; k++) {
1306 p1 = &mesh->point[k];
1307 assert ( p1->flag < mesh->base );
1308 }
1309#endif
1310
1311 double isqhmax = 1./(MMG5_HMAXCOE*MMG5_HMAXCOE);
1312
1317 /* mark array will be used only for non-manifold points */
1318 int *mark;
1319 MMG5_SAFE_CALLOC(mark,mesh->np+1,int,return 0);
1320
1321 for (k=1; k<=mesh->nt; k++) {
1322 ptt = &mesh->tria[k];
1323 if ( !MG_EOK(ptt) ) continue;
1324
1325 for (i=0; i<3; i++) {
1326 MMG5_int ipa = ptt->v[MMG5_iprv2[i]];
1327 MMG5_int ipb = ptt->v[MMG5_inxt2[i]];
1328 p1 = &mesh->point[ipa];
1329 MMG5_pPoint p2 = &mesh->point[ipb];
1330
1331 if ( (!(MG_NOM & p1->tag)) && !(MG_NOM & p2->tag) ) {
1332 continue;
1333 }
1334
1335 double u[3];
1336 u[0] = p1->c[0] - p2->c[0];
1337 u[1] = p1->c[1] - p2->c[1];
1338 u[2] = p1->c[2] - p2->c[2];
1339
1340 tensordot[0] = u[0]*u[0];
1341 tensordot[1] = u[0]*u[1];
1342 tensordot[2] = u[0]*u[2];
1343 tensordot[3] = u[1]*u[1];
1344 tensordot[4] = u[1]*u[2];
1345 tensordot[5] = u[2]*u[2];
1346
1347 if ( MG_NOM & p1->tag ) {
1348 iadr = 6*ipa;
1349 for ( j=0; j<6; ++j ) {
1350 met->m[iadr+j] += tensordot[j];
1351 }
1352 mark[ipa]++;
1353 }
1354
1355 if ( MG_NOM & p2->tag ) {
1356 iadr = 6*ipb;
1357 for ( j=0; j<6; ++j ) {
1358 met->m[iadr+j] += tensordot[j];
1359 }
1360 mark[ipb]++;
1361 }
1362 }
1363 }
1364
1365 for (k=1; k<=mesh->np; k++) {
1366 p1 = &mesh->point[k];
1367 if ( !mark[k] ) {
1368 continue;
1369 }
1370
1371 p1->flag = mesh->base;
1372
1373 /* Metric = nedges/dim * inv (sum(tensor_dot(edges,edges))).
1374 * sum(tensor_dot) is stored in sol->m so reuse tensordot to
1375 * compute M. */
1376 iadr = 6*k;
1377 if ( !MMG5_invmat(met->m+iadr,tensordot) ) {
1378 /* Non invertible matrix: impose isqhmax, it will be truncated by hmax
1379 * later */
1380 fprintf(stdout, " ## Warning: %s: %d: non invertible matrix."
1381 " Impose hmax size at point\n",__func__,__LINE__);
1382 met->m[iadr+0] = isqhmax;
1383 met->m[iadr+2] = 0;
1384 met->m[iadr+3] = isqhmax;
1385 met->m[iadr+4] = 0;
1386 met->m[iadr+5] = isqhmax;
1387 continue;
1388 }
1389
1390 double dd = (double)mark[k]/3.;
1391
1392 for ( j=0; j<6; ++j ) {
1393 met->m[iadr+j] = dd*tensordot[j];
1394 }
1395 }
1396
1397 MMG5_SAFE_FREE(mark);
1398
1399
1400 /* Step 2: travel the triangles to treat the other type of points: On corner
1401 * or ridge point, try to compute 3D unit tensor, on other points, projection
1402 * of the bal of point onto the tangent plane and computation of the 2D unit
1403 * tensor. */
1404 for (k=1; k<=mesh->nt; k++) {
1405 ptt = &mesh->tria[k];
1406 if ( !MG_EOK(ptt) ) continue;
1407
1408 for (i=0; i<3; i++) {
1409 ip = ptt->v[i];
1410
1411 p1 = &mesh->point[ip];
1412 if ( p1->flag == mesh->base ) {
1413 continue;
1414 }
1415
1416 iadr = 6*ip;
1417 m = &met->m[iadr];
1418
1419 if ( MG_CRN & p1->tag ) {
1426 int ier = MMGS_unitTensor_3D( mesh, k, i, p1, m);
1427
1428 if ( !ier ) {
1429 /* Non invertible matrix: compute the 2D unit tensor */
1430 ier = MMGS_unitTensor_2D( mesh, k, i, p1, m, isqhmax);
1431 }
1432
1433 if ( !ier ) {
1434 fprintf(stderr,"\n ## Error: %s: unable to compute anisotropic unit"
1435 " tensor at corner point %"MMG5_PRId".\n",__func__,MMGS_indPt(mesh,ip));
1436 return 0;
1437 }
1438 p1->flag = mesh->base;
1439 }
1440 else if ( MG_REQ & p1->tag ) {
1443 if ( ! MMGS_unitTensor_2D( mesh, k, i, p1, m, isqhmax) ) {
1444 fprintf(stderr,"\n ## Error: %s: unable to compute anisotropic unit"
1445 " tensor at required point %"MMG5_PRId".\n",__func__,MMGS_indPt(mesh,ip));
1446 return 0;
1447 }
1448 p1->flag = mesh->base;
1449 }
1450 else if ( p1->tag & MG_GEO && !(p1->tag & MG_NOM) ) {
1454 int ier = MMGS_unitTensor_3D( mesh, k, i, p1, m);
1455
1456 if ( !ier ) {
1457 /* Non invertible matrix: compute the 2D unit tensor */
1458 ier = MMGS_unitTensor_2D( mesh, k, i, p1, m, isqhmax);
1459 }
1460
1461 if ( !ier ) {
1462 fprintf(stderr,"\n ## Error: %s: unable to compute anisotropic unit"
1463 " tensor at ridge point %"MMG5_PRId".\n",__func__,
1464 MMGS_indPt(mesh,ip));
1465 }
1466 p1->flag = mesh->base;
1467 }
1468 else {
1472 assert ( !(MG_NOM & p1->tag) ); // non-manifold points should have been already treated
1473
1474 if ( ! MMGS_unitTensor_2D( mesh, k, i, p1, m, isqhmax) ) {
1475 fprintf(stderr,"\n ## Error: %s: unable to compute anisotropic unit"
1476 " tensor at required point %"MMG5_PRId".\n",__func__,
1477 MMGS_indPt(mesh,ip));
1478 return 0;
1479 }
1480 p1->flag = mesh->base;
1481 }
1482 /* Check metric */
1483 double lambda[3],vp[3][3];
1484 if (!MMG5_eigenv3d(1,met->m+iadr,lambda,vp) ) {
1485 fprintf(stdout, " ## Warning: %s: %d: non diagonalizable metric.",
1486 __func__,__LINE__);
1487 }
1488
1489 assert ( lambda[0] > 0. && lambda[1] > 0. && lambda[2] > 0.
1490 && "Negative eigenvalue" );
1491 assert ( isfinite(lambda[0]) && isfinite(lambda[1]) && isfinite(lambda[2])
1492 && "Infinite eigenvalue" );
1493 }
1494 }
1495
1497#ifndef NDEBUG
1498 for (k=1; k<=mesh->np; k++) {
1499 p1 = &mesh->point[k];
1500 if ( p1->flag != mesh->base ) {
1501 continue;
1502 }
1503 iadr = 6*k;
1504
1505 /* Check metric */
1506 double lambda[3],vp[3][3];
1507 if (!MMG5_eigenv3d(1,met->m+iadr,lambda,vp) ) {
1508 fprintf(stdout, " ## Warning: %s: %d: non diagonalizable metric.",
1509 __func__,__LINE__);
1510 }
1511
1512 assert ( lambda[0] > 0. && lambda[1] > 0. && lambda[2] > 0.
1513 && "Negative eigenvalue" );
1514 assert ( isfinite(lambda[0]) && isfinite(lambda[1]) && isfinite(lambda[2])
1515 && "Infinite eigenvalue" );
1516 }
1517#endif
1518
1521
1522 return 1;
1523}
1524
1526 double hsiz;
1527 int type;
1528
1529 /* Set solution size */
1530 if ( mesh->info.ani ) {
1531 met->size = 6;
1532 type = 3;
1533 }
1534 else {
1535 met->size = 1;
1536 type = 1;
1537 }
1538
1539 /* Memory alloc */
1540 if ( !MMGS_Set_solSize(mesh,met,MMG5_Vertex,mesh->np,type) )
1541 return 0;
1542
1543 if ( !MMG5_Compute_constantSize(mesh,met,&hsiz) )
1544 return 0;
1545
1546 mesh->info.hsiz = hsiz;
1547
1548 MMG5_Set_constantSize(mesh,met,hsiz);
1549
1550 return 1;
1551}
1552
1553int MMGS_Compute_eigenv(double m[6],double lambda[3],double vp[3][3]) {
1554
1555 return MMG5_eigenv3d(1,m,lambda,vp);
1556
1557}
1558
1560
1561 /* sol */
1562 if ( !sol ) return;
1563
1564 if ( sol->m )
1565 MMG5_DEL_MEM(mesh,sol->m);
1566
1567 if ( sol->namein ) {
1569 }
1570
1571 if ( sol->nameout ) {
1573 }
1574
1575 memset ( sol, 0x0, sizeof(MMG5_Sol) );
1576
1577 /* Reset state to a scalar status */
1578 sol->dim = 3;
1579 sol->ver = 2;
1580 sol->size = 1;
1581 sol->type = 1;
1582
1583 return;
1584}
1585
1587
1588 return MMG5_Clean_isoEdges(mesh);
1589}
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)
int MMGS_Set_inputMeshName(MMG5_pMesh mesh, const char *meshin)
int MMGS_Set_inputSolName(MMG5_pMesh mesh, MMG5_pSol sol, const char *solin)
int MMGS_Set_solSize(MMG5_pMesh mesh, MMG5_pSol sol, int typEntity, MMG5_int np, int typSol)
int MMGS_Set_outputMeshName(MMG5_pMesh mesh, const char *meshout)
int MMGS_Set_dparameter(MMG5_pMesh mesh, MMG5_pSol sol, int dparam, double val)
int MMGS_Set_outputSolName(MMG5_pMesh mesh, MMG5_pSol sol, const char *solout)
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:365
API headers for the mmgs library.
LIBMMGS_EXPORT int(* MMGS_doSol)(MMG5_pMesh mesh, MMG5_pSol met)
Definition: mmgsexterns.c:9
#define MMGS_LMAX
Definition: libmmgs.h:50
@ MMGS_IPARAM_keepRef
Definition: libmmgs.h:69
@ MMGS_IPARAM_nreg
Definition: libmmgs.h:74
@ MMGS_IPARAM_optim
Definition: libmmgs.h:70
@ MMGS_IPARAM_xreg
Definition: libmmgs.h:75
@ MMGS_DPARAM_hgrad
Definition: libmmgs.h:88
@ MMGS_IPARAM_nomove
Definition: libmmgs.h:73
@ MMGS_IPARAM_renum
Definition: libmmgs.h:80
@ MMGS_IPARAM_numsubdomain
Definition: libmmgs.h:79
@ MMGS_IPARAM_nosizreq
Definition: libmmgs.h:82
@ MMGS_DPARAM_angleDetection
Definition: libmmgs.h:83
@ MMGS_IPARAM_verbose
Definition: libmmgs.h:62
@ MMGS_IPARAM_angle
Definition: libmmgs.h:65
@ MMGS_IPARAM_isoref
Definition: libmmgs.h:68
@ MMGS_DPARAM_hsiz
Definition: libmmgs.h:86
@ MMGS_IPARAM_debug
Definition: libmmgs.h:64
@ MMGS_IPARAM_noswap
Definition: libmmgs.h:72
@ MMGS_DPARAM_ls
Definition: libmmgs.h:90
@ MMGS_DPARAM_hmin
Definition: libmmgs.h:84
@ MMGS_IPARAM_iso
Definition: libmmgs.h:66
@ MMGS_DPARAM_hausd
Definition: libmmgs.h:87
@ MMGS_IPARAM_mem
Definition: libmmgs.h:63
@ MMGS_DPARAM_rmc
Definition: libmmgs.h:91
@ MMGS_IPARAM_isosurf
Definition: libmmgs.h:67
@ MMGS_DPARAM_hgradreq
Definition: libmmgs.h:89
@ MMGS_DPARAM_hmax
Definition: libmmgs.h:85
@ MMGS_IPARAM_noinsert
Definition: libmmgs.h:71
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)
int MMGS_Get_adjaVerticesFast(MMG5_pMesh mesh, MMG5_int ip, MMG5_int start, MMG5_int lispoi[MMGS_LMAX])
Return adjacent elements of a triangle.
void MMGS_destockOptions(MMG5_pMesh mesh, MMG5_Info *info)
int MMGS_stockOptions(MMG5_pMesh mesh, MMG5_Info *info)
static int MMGS_unitTensor_3D(MMG5_pMesh mesh, MMG5_int k, int i, MMG5_pPoint p1, double *m)
int MMGS_usage(char *prog)
Definition: libmmgs_tools.c:83
int MMGS_Get_numberOfNonBdyEdges(MMG5_pMesh mesh, MMG5_int *nb_edges)
int MMGS_freeLocalPar(MMG5_pMesh mesh)
int MMGS_Get_adjaTri(MMG5_pMesh mesh, MMG5_int kel, MMG5_int listri[3])
Return adjacent elements of a triangle.
void MMGS_setfunc(MMG5_pMesh mesh, MMG5_pSol met)
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)
int MMGS_doSol_iso(MMG5_pMesh mesh, MMG5_pSol met)
int MMGS_Clean_isoSurf(MMG5_pMesh mesh)
void MMGS_Free_solutions(MMG5_pMesh mesh, MMG5_pSol sol)
int MMGS_Get_nonBdyEdge(MMG5_pMesh mesh, MMG5_int *e0, MMG5_int *e1, MMG5_int *ref, MMG5_int idx)
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])
int MMGS_Set_constantSize(MMG5_pMesh mesh, MMG5_pSol met)
@ MMG5_Tensor
Definition: libmmgtypes.h:215
@ MMG5_Vertex
Definition: libmmgtypes.h:224
void MMG5_advancedUsage(void)
Definition: libtools.c:302
void MMG5_mmgUsage(char *prog)
Definition: libtools.c:210
void MMG5_paramUsage1(void)
Definition: libtools.c:239
void MMG5_mmgDefaultValues(MMG5_pMesh mesh)
Definition: libtools.c:70
void MMG5_paramUsage2(void)
Definition: libtools.c:258
#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)
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 a MMG mesh.
Definition: libmmgtypes.h:305
MMG5_int b
Definition: libmmgtypes.h:306
MMG5_int ref
Definition: libmmgtypes.h:307
MMG5_int a
Definition: libmmgtypes.h:306
Store input parameters of the run.
Definition: libmmgtypes.h:516
int8_t iso
Definition: libmmgtypes.h:534
double hsiz
Definition: libmmgtypes.h:518
int8_t isosurf
Definition: libmmgtypes.h:535
uint8_t ani
Definition: libmmgtypes.h:546
int8_t lag
Definition: libmmgtypes.h:540
MMG5_pPar par
Definition: libmmgtypes.h:517
uint8_t optim
Definition: libmmgtypes.h:546
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_int ntmax
Definition: libmmgtypes.h:612
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
char * nameout
Definition: libmmgtypes.h:653
MMG5_int mark
Definition: libmmgtypes.h:618
MMG5_int * adja
Definition: libmmgtypes.h:624
MMG5_int npmax
Definition: libmmgtypes.h:612
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:642
MMG5_int namax
Definition: libmmgtypes.h:612
MMG5_int base
Definition: libmmgtypes.h:616
MMG5_int nt
Definition: libmmgtypes.h:612
MMG5_pTria tria
Definition: libmmgtypes.h:647
MMG5_int np
Definition: libmmgtypes.h:612
MMG5_pEdge edge
Definition: libmmgtypes.h:649
MMG5_int na
Definition: libmmgtypes.h:612
char * namein
Definition: libmmgtypes.h:652
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 xp
Definition: libmmgtypes.h:279
MMG5_int flag
Definition: libmmgtypes.h:282
char * nameout
Definition: libmmgtypes.h:674
char * namein
Definition: libmmgtypes.h:673
double * m
Definition: libmmgtypes.h:671
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
double n2[3]
Definition: libmmgtypes.h:295
double n1[3]
Definition: libmmgtypes.h:295