Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
intmet_2d.c
Go to the documentation of this file.
1/* =============================================================================
2** This file is part of the mmg software package for the tetrahedral
3** mesh modification.
4** Copyright (c) Bx INP/CNRS/Inria/UBordeaux/UPMC, 2004-
5**
6** mmg is free software: you can redistribute it and/or modify it
7** under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation, either version 3 of the License, or
9** (at your option) any later version.
10**
11** mmg is distributed in the hope that it will be useful, but WITHOUT
12** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13** FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14** License for more details.
15**
16** You should have received a copy of the GNU Lesser General Public
17** License and of the GNU General Public License along with mmg (in
18** files COPYING.LESSER and COPYING). If not, see
19** <http://www.gnu.org/licenses/>. Please read their terms carefully and
20** use this copy of the mmg distribution only if you accept them.
21** =============================================================================
22*/
34#include "libmmg2d_private.h"
35
36/* Interpolation of isotropic metric met along edge i of triangle k, according to parameter s;
37 ip = index of the new point */
38int MMG2D_intmet_iso(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int k,int8_t i,MMG5_int ip,double s) {
39 MMG5_pTria pt;
40 MMG5_int ip1,ip2;
41 int8_t i1,i2;
42
43 pt = &mesh->tria[k];
44 i1 = MMG5_inxt2[i];
45 i2 = MMG5_iprv2[i];
46 ip1 = pt->v[i1];
47 ip2 = pt->v[i2];
48 met->m[ip] = (1.0-s)*met->m[ip1] + s*met->m[ip2];
49
50 return 1;
51}
52
53/* Interpolation of metrics m and n according to parameter s; result is stored in mr. A simultaneous reduction of both matrices is performed and the sizes are interpolated. */
54int MMG5_interpmet22(MMG5_pMesh mesh,double *m,double *n,double s,double *mr) {
55 double det,imn[4],dd,den,sqDelta,trimn,lambda[2],vp[2][2],dm[2];
56 double dn[2],vnorm,d0,d1,ip[4];
57 static int8_t mmgWarn0=0,mmgWarn1=0;
58
59 /* Compute imn = M^{-1}N */
60 det = m[0]*m[2] - m[1]*m[1];
61 if ( fabs(det) < MMG5_EPS*MMG5_EPS ) {
62 if ( !mmgWarn0 ) {
63 mmgWarn0 = 1;
64 fprintf(stderr,"\n ## Error: %s: null metric det : %E \n",
65 __func__,det);
66 }
67 return 0;
68 }
69 det = 1.0 / det;
70
71 imn[0] = det * ( m[2]*n[0] - m[1]*n[1]);
72 imn[1] = det * ( m[2]*n[1] - m[1]*n[2]);
73 imn[2] = det * (-m[1]*n[0] + m[0]*n[1]);
74 imn[3] = det * (-m[1]*n[1] + m[0]*n[2]);
75 dd = imn[0] - imn[3];
76 sqDelta = sqrt(fabs(dd*dd + 4.0*imn[1]*imn[2]));
77 trimn = imn[0] + imn[3];
78
79 lambda[0] = 0.5 * (trimn - sqDelta);
80 if ( lambda[0] < 0.0 ) {
81 if ( !mmgWarn1 ) {
82 mmgWarn1 = 1;
83 fprintf(stderr,"\n ## Error: %s: at least 1 negative eigenvalue: %f \n",
84 __func__,lambda[0]);
85 }
86 return 0;
87 }
88
89 /* First case : matrices m and n are homothetic: n = lambda0*m */
90 if ( sqDelta < MMG5_EPS ) {
91 /* Diagonalize m and truncate eigenvalues : trimn, det, etc... are reused */
92 if ( fabs(m[1]) <= MMG5_EPS || fabs(n[1]) <= MMG5_EPS ) {
93 dm[0] = m[0];
94 dm[1] = m[2];
95 vp[0][0] = 1;
96 vp[0][1] = 0;
97 vp[1][0] = 0;
98 vp[1][1] = 1;
99 }
100 else {
101 MMG5_eigensym( m, dm, vp );
102
103 vp[0][0] = vp[0][0];
104 vp[0][1] = vp[0][1];
105
106 vp[1][0] = vp[1][0];
107 vp[1][1] = vp[1][1];
108 }
109
110 /* Eigenvalues of metric n */
111 dn[0] = lambda[0]*dm[0];
112 dn[1] = lambda[0]*dm[1];
113
114 /* Diagonal values of the intersected metric */
115 dd = dn[0]*dm[0];
116 den = (1.0-s)*(1.0-s)*dn[0] + s*s*dm[0] + 2.0*s*(1.0-s)*sqrt(dd);
117
118 /* If den is too small (should not happen) simply interpolate diagonal values; else interpolate sizes */
119 if ( den < MMG5_EPS ) d0 = (1.0-s)*dm[0] + s*dn[0];
120 else d0 = dd / den;
121
122 dd = dn[1]*dm[1];
123 den = (1.0-s)*(1.0-s)*dn[1] + s*s*dm[1] + 2.0*s*(1.0-s)*sqrt(dd);
124
125 if ( den < MMG5_EPS ) d1 = (1.0-s)*dm[1] + s*dn[1];
126 else d1 = dd / den;
127
128 /* Intersected metric = P diag(d0,d1){^t}P, P = (vp[0], vp[1]) stored in columns */
129 mr[0] = d0*vp[0][0]*vp[0][0] + d1*vp[1][0]*vp[1][0];
130 mr[1] = d0*vp[0][0]*vp[0][1] + d1*vp[1][0]*vp[1][1];
131 mr[2] = d0*vp[0][1]*vp[0][1] + d1*vp[1][1]*vp[1][1];
132
133 return 1;
134 }
135
136 /* Second case: both eigenvalues of imn are distinct ; theory says qf associated to m and n
137 are diagonalizable in basis (vp[0], vp[1]) - the coreduction basis */
138 else {
139 lambda[1] = 0.5 * (trimn + sqDelta);
140 assert(lambda[1] >= 0.0);
141
142 vp[0][0] = imn[1];
143 vp[0][1] = (lambda[0] - imn[0]);
144 vnorm = sqrt(vp[0][0]*vp[0][0] + vp[0][1]*vp[0][1]);
145
146 if ( vnorm < MMG5_EPS ) {
147 vp[0][0] = (lambda[0] - imn[3]);
148 vp[0][1] = imn[2];
149 vnorm = sqrt(vp[0][0]*vp[0][0] + vp[0][1]*vp[0][1]);
150 }
151
152 vnorm = 1.0 / vnorm;
153 vp[0][0] *= vnorm;
154 vp[0][1] *= vnorm;
155
156 vp[1][0] = imn[1];
157 vp[1][1] = (lambda[1] - imn[0]);
158 vnorm = sqrt(vp[1][0]*vp[1][0] + vp[1][1]*vp[1][1]);
159
160 if ( vnorm < MMG5_EPS ) {
161 vp[1][0] = (lambda[1] - imn[3]);
162 vp[1][1] = imn[2];
163 vnorm = sqrt(vp[1][0]*vp[1][0] + vp[1][1]*vp[1][1]);
164 }
165
166 vnorm = 1.0 / vnorm;
167 vp[1][0] *= vnorm;
168 vp[1][1] *= vnorm;
169
170 /* Compute diagonal values in simultaneous reduction basis */
171 dm[0] = m[0]*vp[0][0]*vp[0][0] + 2.0*m[1]*vp[0][0]*vp[0][1] + m[2]*vp[0][1]*vp[0][1];
172 dm[1] = m[0]*vp[1][0]*vp[1][0] + 2.0*m[1]*vp[1][0]*vp[1][1] + m[2]*vp[1][1]*vp[1][1];
173 dn[0] = n[0]*vp[0][0]*vp[0][0] + 2.0*n[1]*vp[0][0]*vp[0][1] + n[2]*vp[0][1]*vp[0][1];
174 dn[1] = n[0]*vp[1][0]*vp[1][0] + 2.0*n[1]*vp[1][0]*vp[1][1] + n[2]*vp[1][1]*vp[1][1];
175
176 /* Diagonal values of the intersected metric */
177 dd = dn[0]*dm[0];
178 den = (1.0-s)*(1.0-s)*dn[0] + s*s*dm[0] + 2.0*s*(1.0-s)*sqrt(dd);
179
180 if ( den < MMG5_EPS ) d0 = (1.0-s)*dm[0] + s*dn[0];
181 else d0 = dd / den;
182
183 dd = dn[1]*dm[1];
184 den = (1.0-s)*(1.0-s)*dn[1] + s*s*dm[1] + 2.0*s*(1.0-s)*sqrt(dd);
185
186 if ( den < MMG5_EPS ) d1 = (1.0-s)*dm[1] + s*dn[1];
187 else d1 = dd / den;
188
189 /* Intersected metric = tP^-1 diag(d0,d1)P^-1, P = (vp[0], vp[1]) stored in columns */
190 det = vp[0][0]*vp[1][1] - vp[0][1]*vp[1][0];
191 if ( fabs(det) < MMG5_EPS ) return 0;
192 det = 1.0 / det;
193
194 ip[0] = vp[1][1]*det;
195 ip[1] = -vp[1][0]*det;
196 ip[2] = -vp[0][1]*det;
197 ip[3] = vp[0][0]*det;
198
199 mr[0] = d0*ip[0]*ip[0] + d1*ip[2]*ip[2];
200 mr[1] = d0*ip[0]*ip[1] + d1*ip[2]*ip[3];
201 mr[2] = d0*ip[1]*ip[1] + d1*ip[3]*ip[3];
202 }
203
204 return 1;
205}
206
207/* Interpolation of anisotropic metric met along edge i of triangle k, according to parameter s;
208 ip = index of the new point */
209int MMG2D_intmet_ani(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int k,int8_t i,MMG5_int ip,double s) {
210 MMG5_pTria pt;
211 double *m1,*m2,*mr;
212#ifndef NDEBUG
213 double det;
214#endif
215 MMG5_int ip1,ip2;
216 int8_t i1,i2;
217 static int8_t mmgWarn=0;
218
219 pt = &mesh->tria[k];
220 i1 = MMG5_inxt2[i];
221 i2 = MMG5_iprv2[i];
222 ip1 = pt->v[i1];
223 ip2 = pt->v[i2];
224 m1 = &met->m[3*ip1];
225 m2 = &met->m[3*ip2];
226 mr = &met->m[3*ip];
227
228 if ( !MMG5_interpmet22(mesh,m1,m2,s,mr) ) {
229 if ( !mmgWarn ) {
230 mmgWarn=1;
231 fprintf(stderr," ## Error: %s: at least 1 naive interpolation.\n",
232 __func__);
233 }
234 mr[0] = (1.0-s)*m1[0] + s*m2[0];
235 mr[1] = (1.0-s)*m1[1] + s*m2[1];
236 mr[2] = (1.0-s)*m1[2] + s*m2[2];
237 }
238
239#ifndef NDEBUG
240 // Check the result
241 det = mr[0]*mr[2] - mr[1]*mr[1];
242 if ( fabs(det) < MMG5_EPS*MMG5_EPS ) {
243 fprintf(stderr,"\n ## Error: %s: interpolation results in null metric det:"
244 " %e \n",__func__,det);
245
246 printf("\nInterpolated metrics:\n");
247
248 double lambda[2],vp[2][2];
249 printf("Metric %" MMG5_PRId " (tag %d): %e %e %e\n",ip1,mesh->point[ip1].tag,m1[0],m1[1],m1[2]);
250
251 MMG5_eigen2(m1,lambda,vp);
252 printf ("eigenval: %e %e\n",lambda[0],lambda[1] );
253 printf ("size: %e %e\n",1./sqrt(lambda[0]),1./sqrt(lambda[1]) );
254 printf ("eigenvec: %e %e\n",vp[0][0],vp[0][1] );
255 printf ("eigenvec: %e %e\n\n",vp[1][0],vp[1][1] );
256
257 printf("Metric %" MMG5_PRId " (tag %d): %e %e %e\n",ip2,mesh->point[ip2].tag,m2[0],m2[1],m2[2]);
258 MMG5_eigen2(m2,lambda,vp);
259 printf ("eigenval: %e %e\n",lambda[0],lambda[1] );
260 printf ("size: %e %e\n",1./sqrt(lambda[0]),1./sqrt(lambda[1]) );
261 printf ("eigenvec: %e %e\n",vp[0][0],vp[0][1] );
262 printf ("eigenvec: %e %e\n\n",vp[1][0],vp[1][1] );
263
264 assert(0);
265 }
266#endif
267
268 return 1;
269}
MMG5_pMesh * mesh
int MMG5_eigensym(double m[3], double lambda[2], double vp[2][2])
Definition: eigenv.c:973
int MMG5_eigen2(double *mm, double *lambda, double vp[2][2])
Find eigenvalues and vectors of a 2x2 matrix.
Definition: eigenv.c:858
#define MMG5_EPS
int MMG5_interpmet22(MMG5_pMesh mesh, double *m, double *n, double s, double *mr)
Definition: intmet_2d.c:54
int MMG2D_intmet_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int8_t i, MMG5_int ip, double s)
Definition: intmet_2d.c:38
int MMG2D_intmet_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int k, int8_t i, MMG5_int ip, double s)
Definition: intmet_2d.c:209
static const uint8_t MMG5_iprv2[3]
static const uint8_t MMG5_inxt2[6]
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_pTria tria
Definition: libmmgtypes.h:647
int16_t tag
Definition: libmmgtypes.h:284
double * m
Definition: libmmgtypes.h:671
MMG5_int v[3]
Definition: libmmgtypes.h:334