Branch data Line data Source code
1 : : /*=========================================================================
2 : :
3 : : Module: $RCSfile: V_TetMetric.cpp,v $
4 : :
5 : : Copyright (c) 2006 Sandia Corporation.
6 : : All rights reserved.
7 : : See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
8 : :
9 : : This software is distributed WITHOUT ANY WARRANTY; without even
10 : : the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 : : PURPOSE. See the above copyright notice for more information.
12 : :
13 : : =========================================================================*/
14 : :
15 : : /*
16 : : *
17 : : * TetMetric.cpp contains quality calculations for Tets
18 : : *
19 : : * This file is part of VERDICT
20 : : *
21 : : */
22 : :
23 : : #define VERDICT_EXPORTS
24 : :
25 : : #include "moab/verdict.h"
26 : : #include "verdict_defines.hpp"
27 : : #include "VerdictVector.hpp"
28 : : #include "V_GaussIntegration.hpp"
29 : : #include <memory.h>
30 : :
31 : : //! the average volume of a tet
32 : : double verdict_tet_size = 0;
33 : :
34 : : /*!
35 : : set the average volume of a tet
36 : : */
37 : 1 : C_FUNC_DEF void v_set_tet_size( double size )
38 : : {
39 : 1 : verdict_tet_size = size;
40 : 1 : }
41 : :
42 : : /*!
43 : : get the weights based on the average size
44 : : of a tet
45 : : */
46 : 46 : int get_weight( VerdictVector& w1, VerdictVector& w2, VerdictVector& w3 )
47 : : {
48 : : static const double rt3 = sqrt( 3.0 );
49 : : static const double root_of_2 = sqrt( 2.0 );
50 : :
51 : 46 : w1.set( 1, 0, 0 );
52 : 46 : w2.set( 0.5, 0.5 * rt3, 0 );
53 : 46 : w3.set( 0.5, rt3 / 6.0, root_of_2 / rt3 );
54 : :
55 [ + - ][ + - ]: 46 : double scale = pow( 6. * verdict_tet_size / determinant( w1, w2, w3 ), 0.3333333333333 );
[ + - ]
56 : :
57 : 46 : w1 *= scale;
58 : 46 : w2 *= scale;
59 : 46 : w3 *= scale;
60 : :
61 : 46 : return 1;
62 : : }
63 : :
64 : : /*!
65 : : the edge ratio of a tet
66 : :
67 : : NB (P. Pebay 01/22/07):
68 : : Hmax / Hmin where Hmax and Hmin are respectively the maximum and the
69 : : minimum edge lengths
70 : : */
71 : 22 : C_FUNC_DEF double v_tet_edge_ratio( int /*num_nodes*/, double coordinates[][3] )
72 : : {
73 [ + - ][ + - ]: 22 : VerdictVector a, b, c, d, e, f;
[ + - ][ + - ]
[ + - ][ + - ]
74 : :
75 : 44 : a.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
76 [ + - ]: 22 : coordinates[1][2] - coordinates[0][2] );
77 : :
78 : 44 : b.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
79 [ + - ]: 22 : coordinates[2][2] - coordinates[1][2] );
80 : :
81 : 44 : c.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
82 [ + - ]: 22 : coordinates[0][2] - coordinates[2][2] );
83 : :
84 : 44 : d.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
85 [ + - ]: 22 : coordinates[3][2] - coordinates[0][2] );
86 : :
87 : 44 : e.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
88 [ + - ]: 22 : coordinates[3][2] - coordinates[1][2] );
89 : :
90 : 44 : f.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
91 [ + - ]: 22 : coordinates[3][2] - coordinates[2][2] );
92 : :
93 [ + - ]: 22 : double a2 = a.length_squared();
94 [ + - ]: 22 : double b2 = b.length_squared();
95 [ + - ]: 22 : double c2 = c.length_squared();
96 [ + - ]: 22 : double d2 = d.length_squared();
97 [ + - ]: 22 : double e2 = e.length_squared();
98 [ + - ]: 22 : double f2 = f.length_squared();
99 : :
100 : : double m2, M2, mab, mcd, mef, Mab, Mcd, Mef;
101 : :
102 [ + + ]: 22 : if( a2 < b2 )
103 : : {
104 : 6 : mab = a2;
105 : 6 : Mab = b2;
106 : : }
107 : : else // b2 <= a2
108 : : {
109 : 16 : mab = b2;
110 : 16 : Mab = a2;
111 : : }
112 [ + + ]: 22 : if( c2 < d2 )
113 : : {
114 : 6 : mcd = c2;
115 : 6 : Mcd = d2;
116 : : }
117 : : else // d2 <= c2
118 : : {
119 : 16 : mcd = d2;
120 : 16 : Mcd = c2;
121 : : }
122 [ + + ]: 22 : if( e2 < f2 )
123 : : {
124 : 8 : mef = e2;
125 : 8 : Mef = f2;
126 : : }
127 : : else // f2 <= e2
128 : : {
129 : 14 : mef = f2;
130 : 14 : Mef = e2;
131 : : }
132 : :
133 [ + + ]: 22 : m2 = mab < mcd ? mab : mcd;
134 [ + + ]: 22 : m2 = m2 < mef ? m2 : mef;
135 : :
136 [ - + ]: 22 : if( m2 < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
137 : :
138 [ + + ]: 22 : M2 = Mab > Mcd ? Mab : Mcd;
139 [ + + ]: 22 : M2 = M2 > Mef ? M2 : Mef;
140 : :
141 : 22 : double edge_ratio = sqrt( M2 / m2 );
142 : :
143 [ + - ][ + - ]: 22 : if( edge_ratio > 0 ) return (double)VERDICT_MIN( edge_ratio, VERDICT_DBL_MAX );
144 [ # # ]: 22 : return (double)VERDICT_MAX( edge_ratio, -VERDICT_DBL_MAX );
145 : : }
146 : :
147 : : /*!
148 : : the scaled jacobian of a tet
149 : :
150 : : minimum of the jacobian divided by the lengths of 3 edge vectors
151 : :
152 : : */
153 : 22 : C_FUNC_DEF double v_tet_scaled_jacobian( int /*num_nodes*/, double coordinates[][3] )
154 : : {
155 : :
156 [ + - ][ + - ]: 22 : VerdictVector side0, side1, side2, side3, side4, side5;
[ + - ][ + - ]
[ + - ][ + - ]
157 : :
158 : 44 : side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
159 [ + - ]: 22 : coordinates[1][2] - coordinates[0][2] );
160 : :
161 : 44 : side1.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
162 [ + - ]: 22 : coordinates[2][2] - coordinates[1][2] );
163 : :
164 : 44 : side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
165 [ + - ]: 22 : coordinates[0][2] - coordinates[2][2] );
166 : :
167 : 44 : side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
168 [ + - ]: 22 : coordinates[3][2] - coordinates[0][2] );
169 : :
170 : 44 : side4.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
171 [ + - ]: 22 : coordinates[3][2] - coordinates[1][2] );
172 : :
173 : 44 : side5.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
174 [ + - ]: 22 : coordinates[3][2] - coordinates[2][2] );
175 : :
176 : : double jacobi;
177 : :
178 [ + - ][ + - ]: 22 : jacobi = side3 % ( side2 * side0 );
179 : :
180 : : // products of lengths squared of each edge attached to a node.
181 [ + - ][ + - ]: 22 : double length_squared[4] = { side0.length_squared() * side2.length_squared() * side3.length_squared(),
[ + - ]
182 [ + - ][ + - ]: 22 : side0.length_squared() * side1.length_squared() * side4.length_squared(),
[ + - ]
183 [ + - ][ + - ]: 22 : side1.length_squared() * side2.length_squared() * side5.length_squared(),
[ + - ]
184 [ + - ][ + - ]: 22 : side3.length_squared() * side4.length_squared() * side5.length_squared() };
[ + - ]
185 : 22 : int which_node = 0;
186 [ + + ]: 22 : if( length_squared[1] > length_squared[which_node] ) which_node = 1;
187 [ + + ]: 22 : if( length_squared[2] > length_squared[which_node] ) which_node = 2;
188 [ + + ]: 22 : if( length_squared[3] > length_squared[which_node] ) which_node = 3;
189 : :
190 : 22 : double length_product = sqrt( length_squared[which_node] );
191 [ - + ]: 22 : if( length_product < fabs( jacobi ) ) length_product = fabs( jacobi );
192 : :
193 [ - + ]: 22 : if( length_product < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
194 : :
195 : : static const double root_of_2 = sqrt( 2.0 );
196 : :
197 : 22 : return (double)( root_of_2 * jacobi / length_product );
198 : : }
199 : :
200 : : /*!
201 : : The radius ratio of a tet
202 : :
203 : : NB (P. Pebay 04/16/07):
204 : : CR / (3.0 * IR) where CR is the circumsphere radius and IR is the inscribed
205 : : sphere radius.
206 : : Note that this metric is similar to the aspect beta of a tet, except that
207 : : it does not return VERDICT_DBL_MAX if the element has negative orientation.
208 : : */
209 : 44 : C_FUNC_DEF double v_tet_radius_ratio( int /*num_nodes*/, double coordinates[][3] )
210 : : {
211 : :
212 : : // Determine side vectors
213 [ + - ][ + + ]: 308 : VerdictVector side[6];
214 : :
215 : 88 : side[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
216 [ + - ]: 44 : coordinates[1][2] - coordinates[0][2] );
217 : :
218 : 88 : side[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
219 [ + - ]: 44 : coordinates[2][2] - coordinates[1][2] );
220 : :
221 : 88 : side[2].set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
222 [ + - ]: 44 : coordinates[0][2] - coordinates[2][2] );
223 : :
224 : 88 : side[3].set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
225 [ + - ]: 44 : coordinates[3][2] - coordinates[0][2] );
226 : :
227 : 88 : side[4].set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
228 [ + - ]: 44 : coordinates[3][2] - coordinates[1][2] );
229 : :
230 : 88 : side[5].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
231 [ + - ]: 44 : coordinates[3][2] - coordinates[2][2] );
232 : :
233 [ + - ][ + - ]: 44 : VerdictVector numerator = side[3].length_squared() * ( side[2] * side[0] ) +
[ + - ][ + - ]
234 [ + - ][ + - ]: 44 : side[2].length_squared() * ( side[3] * side[0] ) +
[ + - ]
235 [ + - ][ + - ]: 88 : side[0].length_squared() * ( side[3] * side[2] );
[ + - ][ + - ]
236 : :
237 : : double area_sum;
238 [ + - ][ + - ]: 44 : area_sum = ( ( side[2] * side[0] ).length() + ( side[3] * side[0] ).length() + ( side[4] * side[1] ).length() +
[ + - ][ + - ]
[ + - ][ + - ]
239 [ + - ][ + - ]: 44 : ( side[3] * side[2] ).length() ) *
240 : 44 : 0.5;
241 : :
242 [ + - ]: 44 : double volume = v_tet_volume( 4, coordinates );
243 : :
244 [ - + ]: 44 : if( fabs( volume ) < VERDICT_DBL_MIN )
245 : 0 : return (double)VERDICT_DBL_MAX;
246 : : else
247 : : {
248 : : double radius_ratio;
249 [ + - ]: 44 : radius_ratio = numerator.length() * area_sum / ( 108 * volume * volume );
250 : :
251 [ + - ]: 44 : return (double)VERDICT_MIN( radius_ratio, VERDICT_DBL_MAX );
252 : : }
253 : : }
254 : :
255 : : /*!
256 : : The radius ratio of a positively-oriented tet, a.k.a. "aspect beta"
257 : :
258 : : NB (P. Pebay 04/16/07):
259 : : CR / (3.0 * IR) where CR is the circumsphere radius and IR is the inscribed
260 : : sphere radius if the element has positive orientation.
261 : : Note that this metric is similar to the radius ratio of a tet, except that
262 : : it returns VERDICT_DBL_MAX if the element has negative orientation.
263 : :
264 : : */
265 : 22 : C_FUNC_DEF double v_tet_aspect_beta( int /*num_nodes*/, double coordinates[][3] )
266 : : {
267 : :
268 : : // Determine side vectors
269 [ + - ][ + + ]: 154 : VerdictVector side[6];
270 : :
271 : 44 : side[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
272 [ + - ]: 22 : coordinates[1][2] - coordinates[0][2] );
273 : :
274 : 44 : side[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
275 [ + - ]: 22 : coordinates[2][2] - coordinates[1][2] );
276 : :
277 : 44 : side[2].set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
278 [ + - ]: 22 : coordinates[0][2] - coordinates[2][2] );
279 : :
280 : 44 : side[3].set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
281 [ + - ]: 22 : coordinates[3][2] - coordinates[0][2] );
282 : :
283 : 44 : side[4].set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
284 [ + - ]: 22 : coordinates[3][2] - coordinates[1][2] );
285 : :
286 : 44 : side[5].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
287 [ + - ]: 22 : coordinates[3][2] - coordinates[2][2] );
288 : :
289 [ + - ][ + - ]: 22 : VerdictVector numerator = side[3].length_squared() * ( side[2] * side[0] ) +
[ + - ][ + - ]
290 [ + - ][ + - ]: 22 : side[2].length_squared() * ( side[3] * side[0] ) +
[ + - ]
291 [ + - ][ + - ]: 44 : side[0].length_squared() * ( side[3] * side[2] );
[ + - ][ + - ]
292 : :
293 : : double area_sum;
294 [ + - ][ + - ]: 22 : area_sum = ( ( side[2] * side[0] ).length() + ( side[3] * side[0] ).length() + ( side[4] * side[1] ).length() +
[ + - ][ + - ]
[ + - ][ + - ]
295 [ + - ][ + - ]: 22 : ( side[3] * side[2] ).length() ) *
296 : 22 : 0.5;
297 : :
298 [ + - ]: 22 : double volume = v_tet_volume( 4, coordinates );
299 : :
300 [ - + ]: 22 : if( volume < VERDICT_DBL_MIN )
301 : 0 : return (double)VERDICT_DBL_MAX;
302 : : else
303 : : {
304 : : double radius_ratio;
305 [ + - ]: 22 : radius_ratio = numerator.length() * area_sum / ( 108 * volume * volume );
306 : :
307 [ + - ]: 22 : return (double)VERDICT_MIN( radius_ratio, VERDICT_DBL_MAX );
308 : : }
309 : : }
310 : :
311 : : /*!
312 : : The aspect ratio of a tet
313 : :
314 : : NB (P. Pebay 01/22/07):
315 : : Hmax / (2 sqrt(6) r) where Hmax and r respectively denote the greatest edge
316 : : length and the inradius of the tetrahedron
317 : : */
318 : 44 : C_FUNC_DEF double v_tet_aspect_ratio( int /*num_nodes*/, double coordinates[][3] )
319 : : {
320 : : static const double normal_coeff = sqrt( 6. ) / 12.;
321 : :
322 : : // Determine side vectors
323 [ + - ][ + - ]: 44 : VerdictVector ab, bc, ac, ad, bd, cd;
[ + - ][ + - ]
[ + - ][ + - ]
324 : :
325 : 88 : ab.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
326 [ + - ]: 44 : coordinates[1][2] - coordinates[0][2] );
327 : :
328 : 88 : ac.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
329 [ + - ]: 44 : coordinates[2][2] - coordinates[0][2] );
330 : :
331 : 88 : ad.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
332 [ + - ]: 44 : coordinates[3][2] - coordinates[0][2] );
333 : :
334 [ + - ][ + - ]: 44 : double detTet = ab % ( ac * ad );
335 : :
336 [ - + ]: 44 : if( detTet < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
337 : :
338 : 88 : bc.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
339 [ + - ]: 44 : coordinates[2][2] - coordinates[1][2] );
340 : :
341 : 88 : bd.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
342 [ + - ]: 44 : coordinates[3][2] - coordinates[1][2] );
343 : :
344 : 88 : cd.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
345 [ + - ]: 44 : coordinates[3][2] - coordinates[2][2] );
346 : :
347 [ + - ]: 44 : double ab2 = ab.length_squared();
348 [ + - ]: 44 : double bc2 = bc.length_squared();
349 [ + - ]: 44 : double ac2 = ac.length_squared();
350 [ + - ]: 44 : double ad2 = ad.length_squared();
351 [ + - ]: 44 : double bd2 = bd.length_squared();
352 [ + - ]: 44 : double cd2 = cd.length_squared();
353 : :
354 [ + + ]: 44 : double A = ab2 > bc2 ? ab2 : bc2;
355 [ + + ]: 44 : double B = ac2 > ad2 ? ac2 : ad2;
356 [ + + ]: 44 : double C = bd2 > cd2 ? bd2 : cd2;
357 [ + + ]: 44 : double D = A > B ? A : B;
358 [ + + ]: 44 : double hm = D > C ? sqrt( D ) : sqrt( C );
359 : :
360 [ + - ][ + - ]: 44 : bd = ab * bc;
361 [ + - ]: 44 : A = bd.length();
362 [ + - ][ + - ]: 44 : bd = ab * ad;
363 [ + - ]: 44 : B = bd.length();
364 [ + - ][ + - ]: 44 : bd = ac * ad;
365 [ + - ]: 44 : C = bd.length();
366 [ + - ][ + - ]: 44 : bd = bc * cd;
367 [ + - ]: 44 : D = bd.length();
368 : :
369 : : double aspect_ratio;
370 : 44 : aspect_ratio = normal_coeff * hm * ( A + B + C + D ) / fabs( detTet );
371 : :
372 [ + - ][ + - ]: 44 : if( aspect_ratio > 0 ) return (double)VERDICT_MIN( aspect_ratio, VERDICT_DBL_MAX );
373 [ # # ]: 44 : return (double)VERDICT_MAX( aspect_ratio, -VERDICT_DBL_MAX );
374 : : }
375 : :
376 : : /*!
377 : : the aspect gamma of a tet
378 : :
379 : : srms^3 / (8.48528137423857*V) where srms = sqrt(sum(Si^2)/6), where Si is the edge length
380 : : */
381 : 22 : C_FUNC_DEF double v_tet_aspect_gamma( int /*num_nodes*/, double coordinates[][3] )
382 : : {
383 : :
384 : : // Determine side vectors
385 [ + - ][ + - ]: 22 : VerdictVector side0, side1, side2, side3, side4, side5;
[ + - ][ + - ]
[ + - ][ + - ]
386 : :
387 : 44 : side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
388 [ + - ]: 22 : coordinates[1][2] - coordinates[0][2] );
389 : :
390 : 44 : side1.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
391 [ + - ]: 22 : coordinates[2][2] - coordinates[1][2] );
392 : :
393 : 44 : side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
394 [ + - ]: 22 : coordinates[0][2] - coordinates[2][2] );
395 : :
396 : 44 : side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
397 [ + - ]: 22 : coordinates[3][2] - coordinates[0][2] );
398 : :
399 : 44 : side4.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
400 [ + - ]: 22 : coordinates[3][2] - coordinates[1][2] );
401 : :
402 : 44 : side5.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
403 [ + - ]: 22 : coordinates[3][2] - coordinates[2][2] );
404 : :
405 [ + - ]: 22 : double volume = fabs( v_tet_volume( 4, coordinates ) );
406 : :
407 [ - + ]: 22 : if( volume < VERDICT_DBL_MIN )
408 : 0 : return (double)VERDICT_DBL_MAX;
409 : : else
410 : : {
411 [ + - ][ + - ]: 22 : double srms = sqrt( ( side0.length_squared() + side1.length_squared() + side2.length_squared() +
[ + - ]
412 [ + - ][ + - ]: 22 : side3.length_squared() + side4.length_squared() + side5.length_squared() ) /
[ + - ]
413 : 22 : 6.0 );
414 : :
415 : 22 : double aspect_ratio_gamma = pow( srms, 3 ) / ( 8.48528137423857 * volume );
416 : 22 : return (double)aspect_ratio_gamma;
417 : : }
418 : : }
419 : :
420 : : /*!
421 : : The aspect frobenius of a tet
422 : :
423 : : NB (P. Pebay 01/22/07):
424 : : Frobenius condition number when the reference element is regular
425 : : */
426 : 44 : C_FUNC_DEF double v_tet_aspect_frobenius( int /*num_nodes*/, double coordinates[][3] )
427 : : {
428 : : static const double normal_exp = 1. / 3.;
429 : :
430 [ + - ][ + - ]: 44 : VerdictVector ab, ac, ad;
[ + - ]
431 : :
432 : 88 : ab.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
433 [ + - ]: 44 : coordinates[1][2] - coordinates[0][2] );
434 : :
435 : 88 : ac.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
436 [ + - ]: 44 : coordinates[2][2] - coordinates[0][2] );
437 : :
438 : 88 : ad.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
439 [ + - ]: 44 : coordinates[3][2] - coordinates[0][2] );
440 : :
441 [ + - ][ + - ]: 44 : double denominator = ab % ( ac * ad );
442 : 44 : denominator *= denominator;
443 : 44 : denominator *= 2.;
444 : 44 : denominator = 3. * pow( denominator, normal_exp );
445 : :
446 [ - + ]: 44 : if( denominator < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
447 : :
448 : : double u[3];
449 [ + - ]: 44 : ab.get_xyz( u );
450 : : double v[3];
451 [ + - ]: 44 : ac.get_xyz( v );
452 : : double w[3];
453 [ + - ]: 44 : ad.get_xyz( w );
454 : :
455 : 44 : double numerator = u[0] * u[0] + u[1] * u[1] + u[2] * u[2];
456 : 44 : numerator += v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
457 : 44 : numerator += w[0] * w[0] + w[1] * w[1] + w[2] * w[2];
458 : 44 : numerator *= 1.5;
459 : 44 : numerator -= v[0] * u[0] + v[1] * u[1] + v[2] * u[2];
460 : 44 : numerator -= w[0] * u[0] + w[1] * u[1] + w[2] * u[2];
461 : 44 : numerator -= w[0] * v[0] + w[1] * v[1] + w[2] * v[2];
462 : :
463 : 44 : double aspect_frobenius = numerator / denominator;
464 : :
465 [ + - ][ + - ]: 44 : if( aspect_frobenius > 0 ) return (double)VERDICT_MIN( aspect_frobenius, VERDICT_DBL_MAX );
466 [ # # ]: 44 : return (double)VERDICT_MAX( aspect_frobenius, -VERDICT_DBL_MAX );
467 : : }
468 : :
469 : : /*!
470 : : The minimum angle of a tet
471 : :
472 : : NB (P. Pebay 01/22/07):
473 : : minimum nonoriented dihedral angle
474 : : */
475 : 44 : C_FUNC_DEF double v_tet_minimum_angle( int /*num_nodes*/, double coordinates[][3] )
476 : : {
477 : : static const double normal_coeff = 180. * .3183098861837906715377675267450287;
478 : :
479 : : // Determine side vectors
480 [ + - ][ + - ]: 44 : VerdictVector ab, bc, ad, cd;
[ + - ][ + - ]
481 : :
482 : 88 : ab.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
483 [ + - ]: 44 : coordinates[1][2] - coordinates[0][2] );
484 : :
485 : 88 : ad.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
486 [ + - ]: 44 : coordinates[3][2] - coordinates[0][2] );
487 : :
488 : 88 : bc.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
489 [ + - ]: 44 : coordinates[2][2] - coordinates[1][2] );
490 : :
491 : 88 : cd.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
492 [ + - ]: 44 : coordinates[3][2] - coordinates[2][2] );
493 : :
494 [ + - ]: 44 : VerdictVector abc = ab * bc;
495 [ + - ]: 44 : double nabc = abc.length();
496 [ + - ]: 44 : VerdictVector abd = ab * ad;
497 [ + - ]: 44 : double nabd = abd.length();
498 [ + - ]: 44 : VerdictVector acd = ad * cd;
499 [ + - ]: 44 : double nacd = acd.length();
500 [ + - ]: 44 : VerdictVector bcd = bc * cd;
501 [ + - ]: 44 : double nbcd = bcd.length();
502 : :
503 [ + - ]: 44 : double alpha = acos( ( abc % abd ) / ( nabc * nabd ) );
504 [ + - ]: 44 : double beta = acos( ( abc % acd ) / ( nabc * nacd ) );
505 [ + - ]: 44 : double gamma = acos( ( abc % bcd ) / ( nabc * nbcd ) );
506 [ + - ]: 44 : double delta = acos( ( abd % acd ) / ( nabd * nacd ) );
507 [ + - ]: 44 : double epsilon = acos( ( abd % bcd ) / ( nabd * nbcd ) );
508 [ + - ]: 44 : double zeta = acos( ( acd % bcd ) / ( nacd * nbcd ) );
509 : :
510 [ + + ]: 44 : alpha = alpha < beta ? alpha : beta;
511 [ + + ]: 44 : alpha = alpha < gamma ? alpha : gamma;
512 [ + + ]: 44 : alpha = alpha < delta ? alpha : delta;
513 [ + - ]: 44 : alpha = alpha < epsilon ? alpha : epsilon;
514 [ + + ]: 44 : alpha = alpha < zeta ? alpha : zeta;
515 : 44 : alpha *= normal_coeff;
516 : :
517 [ - + ]: 44 : if( alpha < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
518 : :
519 [ + - ][ + - ]: 44 : if( alpha > 0 ) return (double)VERDICT_MIN( alpha, VERDICT_DBL_MAX );
520 [ # # ]: 44 : return (double)VERDICT_MAX( alpha, -VERDICT_DBL_MAX );
521 : : }
522 : :
523 : : /*!
524 : : The collapse ratio of a tet
525 : : */
526 : 44 : C_FUNC_DEF double v_tet_collapse_ratio( int /*num_nodes*/, double coordinates[][3] )
527 : : {
528 : : // Determine side vectors
529 [ + - ][ + - ]: 44 : VerdictVector e01, e02, e03, e12, e13, e23;
[ + - ][ + - ]
[ + - ][ + - ]
530 : :
531 : 88 : e01.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
532 [ + - ]: 44 : coordinates[1][2] - coordinates[0][2] );
533 : :
534 : 88 : e02.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
535 [ + - ]: 44 : coordinates[2][2] - coordinates[0][2] );
536 : :
537 : 88 : e03.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
538 [ + - ]: 44 : coordinates[3][2] - coordinates[0][2] );
539 : :
540 : 88 : e12.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
541 [ + - ]: 44 : coordinates[2][2] - coordinates[1][2] );
542 : :
543 : 88 : e13.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
544 [ + - ]: 44 : coordinates[3][2] - coordinates[1][2] );
545 : :
546 : 88 : e23.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
547 [ + - ]: 44 : coordinates[3][2] - coordinates[2][2] );
548 : :
549 : : double l[6];
550 [ + - ]: 44 : l[0] = e01.length();
551 [ + - ]: 44 : l[1] = e02.length();
552 [ + - ]: 44 : l[2] = e03.length();
553 [ + - ]: 44 : l[3] = e12.length();
554 [ + - ]: 44 : l[4] = e13.length();
555 [ + - ]: 44 : l[5] = e23.length();
556 : :
557 : : // Find longest edge for each bounding triangle of tetrahedron
558 [ + + ]: 44 : double l012 = l[4] > l[0] ? l[4] : l[0];
559 [ + + ]: 44 : l012 = l[1] > l012 ? l[1] : l012;
560 [ + + ]: 44 : double l031 = l[0] > l[2] ? l[0] : l[2];
561 [ + + ]: 44 : l031 = l[3] > l031 ? l[3] : l031;
562 [ + + ]: 44 : double l023 = l[2] > l[1] ? l[2] : l[1];
563 [ + + ]: 44 : l023 = l[5] > l023 ? l[5] : l023;
564 [ + + ]: 44 : double l132 = l[4] > l[3] ? l[4] : l[3];
565 [ + + ]: 44 : l132 = l[5] > l132 ? l[5] : l132;
566 : :
567 : : // Compute collapse ratio for each vertex/triangle pair
568 [ + - ]: 44 : VerdictVector N;
569 : : double h, magN;
570 : : double cr;
571 : : double crMin;
572 : :
573 [ + - ][ + - ]: 44 : N = e01 * e02;
574 [ + - ]: 44 : magN = N.length();
575 [ + - ]: 44 : h = ( e03 % N ) / magN; // height of vertex 3 above 0-1-2
576 : 44 : crMin = h / l012; // ratio of height to longest edge of 0-1-2
577 : :
578 [ + - ][ + - ]: 44 : N = e03 * e01;
579 [ + - ]: 44 : magN = N.length();
580 [ + - ]: 44 : h = ( e02 % N ) / magN; // height of vertex 2 above 0-3-1
581 : 44 : cr = h / l031; // ratio of height to longest edge of 0-3-1
582 [ + + ]: 44 : if( cr < crMin ) crMin = cr;
583 : :
584 [ + - ][ + - ]: 44 : N = e02 * e03;
585 [ + - ]: 44 : magN = N.length();
586 [ + - ]: 44 : h = ( e01 % N ) / magN; // height of vertex 1 above 0-2-3
587 : 44 : cr = h / l023; // ratio of height to longest edge of 0-2-3
588 [ + + ]: 44 : if( cr < crMin ) crMin = cr;
589 : :
590 [ + - ][ + - ]: 44 : N = e12 * e13;
591 [ + - ]: 44 : magN = N.length();
592 [ + - ]: 44 : h = ( e01 % N ) / magN; // height of vertex 0 above 1-3-2
593 : 44 : cr = h / l132; // ratio of height to longest edge of 1-3-2
594 [ + + ]: 44 : if( cr < crMin ) crMin = cr;
595 : :
596 [ - + ]: 44 : if( crMin < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
597 [ + - ][ + - ]: 44 : if( crMin > 0 ) return (double)VERDICT_MIN( crMin, VERDICT_DBL_MAX );
598 [ # # ]: 44 : return (double)VERDICT_MAX( crMin, -VERDICT_DBL_MAX );
599 : : }
600 : :
601 : : /*!
602 : : the volume of a tet
603 : :
604 : : 1/6 * jacobian at a corner node
605 : : */
606 : 135 : C_FUNC_DEF double v_tet_volume( int /*num_nodes*/, double coordinates[][3] )
607 : : {
608 : :
609 : : // Determine side vectors
610 [ + - ][ + - ]: 135 : VerdictVector side0, side2, side3;
[ + - ]
611 : :
612 : 270 : side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
613 [ + - ]: 135 : coordinates[1][2] - coordinates[0][2] );
614 : :
615 : 270 : side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
616 [ + - ]: 135 : coordinates[0][2] - coordinates[2][2] );
617 : :
618 : 270 : side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
619 [ + - ]: 135 : coordinates[3][2] - coordinates[0][2] );
620 : :
621 [ + - ][ + - ]: 135 : return (double)( ( side3 % ( side2 * side0 ) ) / 6.0 );
622 : : }
623 : :
624 : : /*!
625 : : the condition of a tet
626 : :
627 : : condition number of the jacobian matrix at any corner
628 : : */
629 : 23 : C_FUNC_DEF double v_tet_condition( int /*num_nodes*/, double coordinates[][3] )
630 : : {
631 : :
632 : : double condition, term1, term2, det;
633 : 23 : double rt3 = sqrt( 3.0 );
634 : 23 : double rt6 = sqrt( 6.0 );
635 : :
636 [ + - ][ + - ]: 23 : VerdictVector side0, side2, side3;
[ + - ]
637 : :
638 : 46 : side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
639 [ + - ]: 23 : coordinates[1][2] - coordinates[0][2] );
640 : :
641 : 46 : side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
642 [ + - ]: 23 : coordinates[0][2] - coordinates[2][2] );
643 : :
644 : 46 : side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
645 [ + - ]: 23 : coordinates[3][2] - coordinates[0][2] );
646 : :
647 [ + - ][ + - ]: 23 : VerdictVector c_1, c_2, c_3;
[ + - ]
648 : :
649 [ + - ]: 23 : c_1 = side0;
650 [ + - ][ + - ]: 23 : c_2 = ( -2 * side2 - side0 ) / rt3;
[ + - ][ + - ]
651 [ + - ][ + - ]: 23 : c_3 = ( 3 * side3 + side2 - side0 ) / rt6;
[ + - ][ + - ]
[ + - ]
652 : :
653 [ + - ][ + - ]: 23 : term1 = c_1 % c_1 + c_2 % c_2 + c_3 % c_3;
[ + - ]
654 [ + - ][ + - ]: 23 : term2 = ( c_1 * c_2 ) % ( c_1 * c_2 ) + ( c_2 * c_3 ) % ( c_2 * c_3 ) + ( c_1 * c_3 ) % ( c_1 * c_3 );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
655 [ + - ][ + - ]: 23 : det = c_1 % ( c_2 * c_3 );
656 : :
657 [ - + ]: 23 : if( det <= VERDICT_DBL_MIN )
658 : 0 : return VERDICT_DBL_MAX;
659 : : else
660 : 23 : condition = sqrt( term1 * term2 ) / ( 3.0 * det );
661 : :
662 : 23 : return (double)condition;
663 : : }
664 : :
665 : : /*!
666 : : the jacobian of a tet
667 : :
668 : : TODO
669 : : */
670 : 23 : C_FUNC_DEF double v_tet_jacobian( int /*num_nodes*/, double coordinates[][3] )
671 : : {
672 [ + - ][ + - ]: 23 : VerdictVector side0, side2, side3;
[ + - ]
673 : :
674 : 46 : side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
675 [ + - ]: 23 : coordinates[1][2] - coordinates[0][2] );
676 : :
677 : 46 : side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
678 [ + - ]: 23 : coordinates[0][2] - coordinates[2][2] );
679 : :
680 : 46 : side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
681 [ + - ]: 23 : coordinates[3][2] - coordinates[0][2] );
682 : :
683 [ + - ][ + - ]: 23 : return (double)( side3 % ( side2 * side0 ) );
684 : : }
685 : :
686 : : /*!
687 : : the shape of a tet
688 : :
689 : : 3/ condition number of weighted jacobian matrix
690 : : */
691 : 24 : C_FUNC_DEF double v_tet_shape( int /*num_nodes*/, double coordinates[][3] )
692 : : {
693 : :
694 : : static const double two_thirds = 2.0 / 3.0;
695 : : static const double root_of_2 = sqrt( 2.0 );
696 : :
697 [ + - ][ + - ]: 24 : VerdictVector edge0, edge2, edge3;
[ + - ]
698 : :
699 : 48 : edge0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
700 [ + - ]: 24 : coordinates[1][2] - coordinates[0][2] );
701 : :
702 : 48 : edge2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
703 [ + - ]: 24 : coordinates[0][2] - coordinates[2][2] );
704 : :
705 : 48 : edge3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
706 [ + - ]: 24 : coordinates[3][2] - coordinates[0][2] );
707 : :
708 [ + - ][ + - ]: 24 : double jacobian = edge3 % ( edge2 * edge0 );
709 [ - + ]: 24 : if( jacobian < VERDICT_DBL_MIN ) { return (double)0.0; }
710 : 24 : double num = 3 * pow( root_of_2 * jacobian, two_thirds );
711 : : double den =
712 [ + - ][ + - ]: 24 : 1.5 * ( edge0 % edge0 + edge2 % edge2 + edge3 % edge3 ) - ( edge0 % -edge2 + -edge2 % edge3 + edge3 % edge0 );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
713 : :
714 [ - + ]: 24 : if( den < VERDICT_DBL_MIN ) return (double)0.0;
715 : :
716 [ + - ]: 24 : return (double)VERDICT_MAX( num / den, 0 );
717 : : }
718 : :
719 : : /*!
720 : : the relative size of a tet
721 : :
722 : : Min(J,1/J), where J is the determinant of the weighted Jacobian matrix
723 : : */
724 : 24 : C_FUNC_DEF double v_tet_relative_size_squared( int /*num_nodes*/, double coordinates[][3] )
725 : : {
726 : : double size;
727 [ + - ][ + - ]: 24 : VerdictVector w1, w2, w3;
[ + - ]
728 [ + - ]: 24 : get_weight( w1, w2, w3 );
729 [ + - ][ + - ]: 24 : double avg_volume = ( w1 % ( w2 * w3 ) ) / 6.0;
730 : :
731 [ + - ]: 24 : double volume = v_tet_volume( 4, coordinates );
732 : :
733 [ - + ]: 24 : if( avg_volume < VERDICT_DBL_MIN )
734 : 0 : return 0.0;
735 : : else
736 : : {
737 : 24 : size = volume / avg_volume;
738 [ - + ]: 24 : if( size <= VERDICT_DBL_MIN ) return 0.0;
739 [ + + ]: 24 : if( size > 1 ) size = (double)( 1 ) / size;
740 : : }
741 : 24 : return (double)( size * size );
742 : : }
743 : :
744 : : /*!
745 : : the shape and size of a tet
746 : :
747 : : Product of the shape and relative size
748 : : */
749 : 1 : C_FUNC_DEF double v_tet_shape_and_size( int num_nodes, double coordinates[][3] )
750 : : {
751 : :
752 : : double shape, size;
753 : 1 : shape = v_tet_shape( num_nodes, coordinates );
754 : 1 : size = v_tet_relative_size_squared( num_nodes, coordinates );
755 : :
756 : 1 : return (double)( shape * size );
757 : : }
758 : :
759 : : /*!
760 : : the distortion of a tet
761 : : */
762 : 23 : C_FUNC_DEF double v_tet_distortion( int num_nodes, double coordinates[][3] )
763 : : {
764 : :
765 : 23 : double distortion = VERDICT_DBL_MAX;
766 : 23 : int number_of_gauss_points = 0;
767 [ + - ]: 23 : if( num_nodes == 4 )
768 : : // for linear tet, the distortion is always 1 because
769 : : // straight edge tets are the target shape for tet
770 : 23 : return 1.0;
771 : :
772 [ # # ]: 0 : else if( num_nodes == 10 )
773 : : // use four integration points for quadratic tet
774 : 0 : number_of_gauss_points = 4;
775 : :
776 : 0 : int number_dims = 3;
777 : 0 : int total_number_of_gauss_points = number_of_gauss_points;
778 : : // use is_tri=1 to indicate this is for tet in 3D
779 : 0 : int is_tri = 1;
780 : :
781 : : double shape_function[maxTotalNumberGaussPoints][maxNumberNodes];
782 : : double dndy1[maxTotalNumberGaussPoints][maxNumberNodes];
783 : : double dndy2[maxTotalNumberGaussPoints][maxNumberNodes];
784 : : double dndy3[maxTotalNumberGaussPoints][maxNumberNodes];
785 : : double weight[maxTotalNumberGaussPoints];
786 : :
787 : : // create an object of GaussIntegration for tet
788 [ # # ]: 0 : GaussIntegration::initialize( number_of_gauss_points, num_nodes, number_dims, is_tri );
789 [ # # ]: 0 : GaussIntegration::calculate_shape_function_3d_tet();
790 [ # # ]: 0 : GaussIntegration::get_shape_func( shape_function[0], dndy1[0], dndy2[0], dndy3[0], weight );
791 : :
792 : : // vector xxi is the derivative vector of coordinates w.r.t local xi coordinate in the
793 : : // computation space
794 : : // vector xet is the derivative vector of coordinates w.r.t local et coordinate in the
795 : : // computation space
796 : : // vector xze is the derivative vector of coordinates w.r.t local ze coordinate in the
797 : : // computation space
798 [ # # ][ # # ]: 0 : VerdictVector xxi, xet, xze, xin;
[ # # ][ # # ]
799 : :
800 : : double jacobian, minimum_jacobian;
801 : 0 : double element_volume = 0.0;
802 : 0 : minimum_jacobian = VERDICT_DBL_MAX;
803 : :
804 : : // calculate element volume
805 : : int ife, ja;
806 [ # # ]: 0 : for( ife = 0; ife < total_number_of_gauss_points; ife++ )
807 : : {
808 [ # # ]: 0 : xxi.set( 0.0, 0.0, 0.0 );
809 [ # # ]: 0 : xet.set( 0.0, 0.0, 0.0 );
810 [ # # ]: 0 : xze.set( 0.0, 0.0, 0.0 );
811 : :
812 [ # # ]: 0 : for( ja = 0; ja < num_nodes; ja++ )
813 : : {
814 [ # # ]: 0 : xin.set( coordinates[ja][0], coordinates[ja][1], coordinates[ja][2] );
815 [ # # ][ # # ]: 0 : xxi += dndy1[ife][ja] * xin;
816 [ # # ][ # # ]: 0 : xet += dndy2[ife][ja] * xin;
817 [ # # ][ # # ]: 0 : xze += dndy3[ife][ja] * xin;
818 : : }
819 : :
820 : : // determinant
821 [ # # ][ # # ]: 0 : jacobian = xxi % ( xet * xze );
822 [ # # ]: 0 : if( minimum_jacobian > jacobian ) minimum_jacobian = jacobian;
823 : :
824 : 0 : element_volume += weight[ife] * jacobian;
825 : : } // element_volume is 6 times the actual volume
826 : :
827 : : // loop through all nodes
828 : : double dndy1_at_node[maxNumberNodes][maxNumberNodes];
829 : : double dndy2_at_node[maxNumberNodes][maxNumberNodes];
830 : : double dndy3_at_node[maxNumberNodes][maxNumberNodes];
831 : :
832 [ # # ]: 0 : GaussIntegration::calculate_derivative_at_nodes_3d_tet( dndy1_at_node, dndy2_at_node, dndy3_at_node );
833 : : int node_id;
834 [ # # ]: 0 : for( node_id = 0; node_id < num_nodes; node_id++ )
835 : : {
836 [ # # ]: 0 : xxi.set( 0.0, 0.0, 0.0 );
837 [ # # ]: 0 : xet.set( 0.0, 0.0, 0.0 );
838 [ # # ]: 0 : xze.set( 0.0, 0.0, 0.0 );
839 : :
840 [ # # ]: 0 : for( ja = 0; ja < num_nodes; ja++ )
841 : : {
842 [ # # ]: 0 : xin.set( coordinates[ja][0], coordinates[ja][1], coordinates[ja][2] );
843 [ # # ][ # # ]: 0 : xxi += dndy1_at_node[node_id][ja] * xin;
844 [ # # ][ # # ]: 0 : xet += dndy2_at_node[node_id][ja] * xin;
845 [ # # ][ # # ]: 0 : xze += dndy3_at_node[node_id][ja] * xin;
846 : : }
847 : :
848 [ # # ][ # # ]: 0 : jacobian = xxi % ( xet * xze );
849 [ # # ]: 0 : if( minimum_jacobian > jacobian ) minimum_jacobian = jacobian;
850 : : }
851 : 0 : distortion = minimum_jacobian / element_volume;
852 : :
853 : 23 : return (double)distortion;
854 : : }
855 : :
856 : : /*!
857 : : the quality metrics of a tet
858 : : */
859 : 22 : C_FUNC_DEF void v_tet_quality( int num_nodes, double coordinates[][3], unsigned int metrics_request_flag,
860 : : TetMetricVals* metric_vals )
861 : : {
862 : :
863 : 22 : memset( metric_vals, 0, sizeof( TetMetricVals ) );
864 : :
865 : : /*
866 : :
867 : : node numbers and edge numbers below
868 : :
869 : :
870 : :
871 : : 3
872 : : + edge 0 is node 0 to 1
873 : : +|+ edge 1 is node 1 to 2
874 : : 3/ | \5 edge 2 is node 0 to 2
875 : : / 4| \ edge 3 is node 0 to 3
876 : : 0 - -|- + 2 edge 4 is node 1 to 3
877 : : \ | + edge 5 is node 2 to 3
878 : : 0\ | /1
879 : : +|/ edge 2 is behind edge 4
880 : : 1
881 : :
882 : :
883 : : */
884 : :
885 : : // lets start with making the vectors
886 [ + - ][ + + ]: 154 : VerdictVector edges[6];
887 : 44 : edges[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
888 [ + - ]: 22 : coordinates[1][2] - coordinates[0][2] );
889 : :
890 : 44 : edges[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
891 [ + - ]: 22 : coordinates[2][2] - coordinates[1][2] );
892 : :
893 : 44 : edges[2].set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
894 [ + - ]: 22 : coordinates[0][2] - coordinates[2][2] );
895 : :
896 : 44 : edges[3].set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
897 [ + - ]: 22 : coordinates[3][2] - coordinates[0][2] );
898 : :
899 : 44 : edges[4].set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
900 [ + - ]: 22 : coordinates[3][2] - coordinates[1][2] );
901 : :
902 : 44 : edges[5].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
903 [ + - ]: 22 : coordinates[3][2] - coordinates[2][2] );
904 : :
905 : : // common numbers
906 : : static const double root_of_2 = sqrt( 2.0 );
907 : :
908 : : // calculate the jacobian
909 : : static const int do_jacobian = V_TET_JACOBIAN | V_TET_VOLUME | V_TET_ASPECT_BETA | V_TET_ASPECT_GAMMA |
910 : : V_TET_SHAPE | V_TET_RELATIVE_SIZE_SQUARED | V_TET_SHAPE_AND_SIZE |
911 : : V_TET_SCALED_JACOBIAN | V_TET_CONDITION;
912 [ + - ][ + - ]: 22 : if( metrics_request_flag & do_jacobian ) { metric_vals->jacobian = (double)( edges[3] % ( edges[2] * edges[0] ) ); }
[ + - ]
913 : :
914 : : // calculate the volume
915 [ + - ]: 22 : if( metrics_request_flag & V_TET_VOLUME ) { metric_vals->volume = (double)( metric_vals->jacobian / 6.0 ); }
916 : :
917 : : // calculate aspect ratio
918 [ + - ]: 22 : if( metrics_request_flag & V_TET_ASPECT_BETA )
919 : : {
920 [ + - ][ + - ]: 22 : double surface_area = ( ( edges[2] * edges[0] ).length() + ( edges[3] * edges[0] ).length() +
[ + - ][ + - ]
921 [ + - ][ + - ]: 22 : ( edges[4] * edges[1] ).length() + ( edges[3] * edges[2] ).length() ) *
[ + - ][ + - ]
922 : 22 : 0.5;
923 : :
924 [ + - ][ + - ]: 22 : VerdictVector numerator = edges[3].length_squared() * ( edges[2] * edges[0] ) +
[ + - ][ + - ]
925 [ + - ][ + - ]: 22 : edges[2].length_squared() * ( edges[3] * edges[0] ) +
[ + - ]
926 [ + - ][ + - ]: 44 : edges[0].length_squared() * ( edges[3] * edges[2] );
[ + - ][ + - ]
927 : :
928 : 22 : double volume = metric_vals->jacobian / 6.0;
929 : :
930 [ - + ]: 22 : if( volume < VERDICT_DBL_MIN )
931 : 0 : metric_vals->aspect_beta = (double)( VERDICT_DBL_MAX );
932 : : else
933 [ + - ]: 22 : metric_vals->aspect_beta = (double)( numerator.length() * surface_area / ( 108 * volume * volume ) );
934 : : }
935 : :
936 : : // calculate the aspect gamma
937 [ + - ]: 22 : if( metrics_request_flag & V_TET_ASPECT_GAMMA )
938 : : {
939 : 22 : double volume = fabs( metric_vals->jacobian / 6.0 );
940 [ - + ]: 22 : if( fabs( volume ) < VERDICT_DBL_MIN )
941 : 0 : metric_vals->aspect_gamma = VERDICT_DBL_MAX;
942 : : else
943 : : {
944 [ + - ][ + - ]: 22 : double srms = sqrt( ( edges[0].length_squared() + edges[1].length_squared() + edges[2].length_squared() +
[ + - ]
945 [ + - ][ + - ]: 22 : edges[3].length_squared() + edges[4].length_squared() + edges[5].length_squared() ) /
[ + - ]
946 : 22 : 6.0 );
947 : :
948 : : // cube the srms
949 : 22 : srms *= ( srms * srms );
950 : 22 : metric_vals->aspect_gamma = (double)( srms / ( 8.48528137423857 * volume ) );
951 : : }
952 : : }
953 : :
954 : : // calculate the shape of the tet
955 [ + - ]: 22 : if( metrics_request_flag & ( V_TET_SHAPE | V_TET_SHAPE_AND_SIZE ) )
956 : : {
957 : : // if the jacobian is non-positive, the shape is 0
958 [ - + ]: 22 : if( metric_vals->jacobian < VERDICT_DBL_MIN ) { metric_vals->shape = (double)0.0; }
959 : : else
960 : : {
961 : : static const double two_thirds = 2.0 / 3.0;
962 : 22 : double num = 3.0 * pow( root_of_2 * metric_vals->jacobian, two_thirds );
963 [ + - ][ + - ]: 22 : double den = 1.5 * ( edges[0] % edges[0] + edges[2] % edges[2] + edges[3] % edges[3] ) -
[ + - ]
964 [ + - ][ + - ]: 22 : ( edges[0] % -edges[2] + -edges[2] % edges[3] + edges[3] % edges[0] );
[ + - ][ + - ]
[ + - ]
965 : :
966 [ - + ]: 22 : if( den < VERDICT_DBL_MIN )
967 : 0 : metric_vals->shape = (double)0.0;
968 : : else
969 [ + - ]: 22 : metric_vals->shape = (double)VERDICT_MAX( num / den, 0 );
970 : : }
971 : : }
972 : :
973 : : // calculate the relative size of the tet
974 [ + - ]: 22 : if( metrics_request_flag & ( V_TET_RELATIVE_SIZE_SQUARED | V_TET_SHAPE_AND_SIZE ) )
975 : : {
976 [ + - ][ + - ]: 22 : VerdictVector w1, w2, w3;
[ + - ]
977 [ + - ]: 22 : get_weight( w1, w2, w3 );
978 [ + - ][ + - ]: 22 : double avg_vol = ( w1 % ( w2 * w3 ) ) / 6;
979 : :
980 [ - + ]: 22 : if( avg_vol < VERDICT_DBL_MIN )
981 : 0 : metric_vals->relative_size_squared = 0.0;
982 : : else
983 : : {
984 : 22 : double tmp = metric_vals->jacobian / ( 6 * avg_vol );
985 [ - + ]: 22 : if( tmp < VERDICT_DBL_MIN )
986 : 0 : metric_vals->relative_size_squared = 0.0;
987 : : else
988 : : {
989 : 22 : tmp *= tmp;
990 [ + - ]: 22 : metric_vals->relative_size_squared = (double)VERDICT_MIN( tmp, 1 / tmp );
991 : : }
992 : : }
993 : : }
994 : :
995 : : // calculate the shape and size
996 [ + - ]: 22 : if( metrics_request_flag & V_TET_SHAPE_AND_SIZE )
997 : 22 : { metric_vals->shape_and_size = (double)( metric_vals->shape * metric_vals->relative_size_squared ); }
998 : :
999 : : // calculate the scaled jacobian
1000 [ + - ]: 22 : if( metrics_request_flag & V_TET_SCALED_JACOBIAN )
1001 : : {
1002 : : // find out which node the normalized jacobian can be calculated at
1003 : : // and it will be the smaller than at other nodes
1004 [ + - ][ + - ]: 22 : double length_squared[4] = { edges[0].length_squared() * edges[2].length_squared() * edges[3].length_squared(),
[ + - ]
1005 [ + - ][ + - ]: 22 : edges[0].length_squared() * edges[1].length_squared() * edges[4].length_squared(),
[ + - ]
1006 [ + - ][ + - ]: 22 : edges[1].length_squared() * edges[2].length_squared() * edges[5].length_squared(),
[ + - ]
1007 [ + - ][ + - ]: 22 : edges[3].length_squared() * edges[4].length_squared() *
1008 [ + - ]: 22 : edges[5].length_squared() };
1009 : :
1010 : 22 : int which_node = 0;
1011 [ + + ]: 22 : if( length_squared[1] > length_squared[which_node] ) which_node = 1;
1012 [ + + ]: 22 : if( length_squared[2] > length_squared[which_node] ) which_node = 2;
1013 [ + + ]: 22 : if( length_squared[3] > length_squared[which_node] ) which_node = 3;
1014 : :
1015 : : // find the scaled jacobian at this node
1016 : 22 : double length_product = sqrt( length_squared[which_node] );
1017 [ - + ]: 22 : if( length_product < fabs( metric_vals->jacobian ) ) length_product = fabs( metric_vals->jacobian );
1018 : :
1019 [ - + ]: 22 : if( length_product < VERDICT_DBL_MIN )
1020 : 0 : metric_vals->scaled_jacobian = (double)VERDICT_DBL_MAX;
1021 : : else
1022 : 22 : metric_vals->scaled_jacobian = (double)( root_of_2 * metric_vals->jacobian / length_product );
1023 : : }
1024 : :
1025 : : // calculate the condition number
1026 [ + - ]: 22 : if( metrics_request_flag & V_TET_CONDITION )
1027 : : {
1028 : : static const double root_of_3 = sqrt( 3.0 );
1029 : : static const double root_of_6 = sqrt( 6.0 );
1030 : :
1031 [ + - ][ + - ]: 22 : VerdictVector c_1, c_2, c_3;
[ + - ]
1032 [ + - ]: 22 : c_1 = edges[0];
1033 [ + - ][ + - ]: 22 : c_2 = ( -2 * edges[2] - edges[0] ) / root_of_3;
[ + - ][ + - ]
1034 [ + - ][ + - ]: 22 : c_3 = ( 3 * edges[3] + edges[2] - edges[0] ) / root_of_6;
[ + - ][ + - ]
[ + - ]
1035 : :
1036 [ + - ][ + - ]: 22 : double term1 = c_1 % c_1 + c_2 % c_2 + c_3 % c_3;
[ + - ]
1037 [ + - ][ + - ]: 22 : double term2 = ( c_1 * c_2 ) % ( c_1 * c_2 ) + ( c_2 * c_3 ) % ( c_2 * c_3 ) + ( c_3 * c_1 ) % ( c_3 * c_1 );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
1038 : :
1039 [ + - ][ + - ]: 22 : double det = c_1 % ( c_2 * c_3 );
1040 : :
1041 [ - + ]: 22 : if( det <= VERDICT_DBL_MIN )
1042 : 0 : metric_vals->condition = (double)VERDICT_DBL_MAX;
1043 : : else
1044 : 22 : metric_vals->condition = (double)( sqrt( term1 * term2 ) / ( 3.0 * det ) );
1045 : : }
1046 : :
1047 : : // calculate the distortion
1048 [ + - ]: 22 : if( metrics_request_flag & V_TET_DISTORTION )
1049 [ + - ]: 22 : { metric_vals->distortion = v_tet_distortion( num_nodes, coordinates ); }
1050 : :
1051 : : // check for overflow
1052 [ + - ]: 22 : if( metrics_request_flag & V_TET_ASPECT_BETA )
1053 : : {
1054 [ + - ]: 22 : if( metric_vals->aspect_beta > 0 )
1055 [ + - ]: 22 : metric_vals->aspect_beta = (double)VERDICT_MIN( metric_vals->aspect_beta, VERDICT_DBL_MAX );
1056 [ + - ]: 22 : metric_vals->aspect_beta = (double)VERDICT_MAX( metric_vals->aspect_beta, -VERDICT_DBL_MAX );
1057 : : }
1058 : :
1059 [ + - ]: 22 : if( metrics_request_flag & V_TET_ASPECT_GAMMA )
1060 : : {
1061 [ + - ]: 22 : if( metric_vals->aspect_gamma > 0 )
1062 [ + - ]: 22 : metric_vals->aspect_gamma = (double)VERDICT_MIN( metric_vals->aspect_gamma, VERDICT_DBL_MAX );
1063 [ + - ]: 22 : metric_vals->aspect_gamma = (double)VERDICT_MAX( metric_vals->aspect_gamma, -VERDICT_DBL_MAX );
1064 : : }
1065 : :
1066 [ + - ]: 22 : if( metrics_request_flag & V_TET_VOLUME )
1067 : : {
1068 [ + - ][ + - ]: 22 : if( metric_vals->volume > 0 ) metric_vals->volume = (double)VERDICT_MIN( metric_vals->volume, VERDICT_DBL_MAX );
1069 [ + - ]: 22 : metric_vals->volume = (double)VERDICT_MAX( metric_vals->volume, -VERDICT_DBL_MAX );
1070 : : }
1071 : :
1072 [ + - ]: 22 : if( metrics_request_flag & V_TET_CONDITION )
1073 : : {
1074 [ + - ]: 22 : if( metric_vals->condition > 0 )
1075 [ + - ]: 22 : metric_vals->condition = (double)VERDICT_MIN( metric_vals->condition, VERDICT_DBL_MAX );
1076 [ + - ]: 22 : metric_vals->condition = (double)VERDICT_MAX( metric_vals->condition, -VERDICT_DBL_MAX );
1077 : : }
1078 : :
1079 [ + - ]: 22 : if( metrics_request_flag & V_TET_JACOBIAN )
1080 : : {
1081 [ + - ]: 22 : if( metric_vals->jacobian > 0 )
1082 [ + - ]: 22 : metric_vals->jacobian = (double)VERDICT_MIN( metric_vals->jacobian, VERDICT_DBL_MAX );
1083 [ + - ]: 22 : metric_vals->jacobian = (double)VERDICT_MAX( metric_vals->jacobian, -VERDICT_DBL_MAX );
1084 : : }
1085 : :
1086 [ + - ]: 22 : if( metrics_request_flag & V_TET_SCALED_JACOBIAN )
1087 : : {
1088 [ + - ]: 22 : if( metric_vals->scaled_jacobian > 0 )
1089 [ + - ]: 22 : metric_vals->scaled_jacobian = (double)VERDICT_MIN( metric_vals->scaled_jacobian, VERDICT_DBL_MAX );
1090 [ + - ]: 22 : metric_vals->scaled_jacobian = (double)VERDICT_MAX( metric_vals->scaled_jacobian, -VERDICT_DBL_MAX );
1091 : : }
1092 : :
1093 [ + - ]: 22 : if( metrics_request_flag & V_TET_SHAPE )
1094 : : {
1095 [ + - ][ + - ]: 22 : if( metric_vals->shape > 0 ) metric_vals->shape = (double)VERDICT_MIN( metric_vals->shape, VERDICT_DBL_MAX );
1096 [ + - ]: 22 : metric_vals->shape = (double)VERDICT_MAX( metric_vals->shape, -VERDICT_DBL_MAX );
1097 : : }
1098 : :
1099 [ + - ]: 22 : if( metrics_request_flag & V_TET_RELATIVE_SIZE_SQUARED )
1100 : : {
1101 [ + - ]: 22 : if( metric_vals->relative_size_squared > 0 )
1102 : : metric_vals->relative_size_squared =
1103 [ + - ]: 22 : (double)VERDICT_MIN( metric_vals->relative_size_squared, VERDICT_DBL_MAX );
1104 : : metric_vals->relative_size_squared =
1105 [ + - ]: 22 : (double)VERDICT_MAX( metric_vals->relative_size_squared, -VERDICT_DBL_MAX );
1106 : : }
1107 : :
1108 [ + - ]: 22 : if( metrics_request_flag & V_TET_SHAPE_AND_SIZE )
1109 : : {
1110 [ + - ]: 22 : if( metric_vals->shape_and_size > 0 )
1111 [ + - ]: 22 : metric_vals->shape_and_size = (double)VERDICT_MIN( metric_vals->shape_and_size, VERDICT_DBL_MAX );
1112 [ + - ]: 22 : metric_vals->shape_and_size = (double)VERDICT_MAX( metric_vals->shape_and_size, -VERDICT_DBL_MAX );
1113 : : }
1114 : :
1115 [ + - ]: 22 : if( metrics_request_flag & V_TET_DISTORTION )
1116 : : {
1117 [ + - ]: 22 : if( metric_vals->distortion > 0 )
1118 [ + - ]: 22 : metric_vals->distortion = (double)VERDICT_MIN( metric_vals->distortion, VERDICT_DBL_MAX );
1119 [ + - ]: 22 : metric_vals->distortion = (double)VERDICT_MAX( metric_vals->distortion, -VERDICT_DBL_MAX );
1120 : : }
1121 : :
1122 [ + - ][ + - ]: 22 : if( metrics_request_flag & V_TET_ASPECT_RATIO ) metric_vals->aspect_ratio = v_tet_aspect_ratio( 4, coordinates );
1123 : :
1124 [ + - ]: 22 : if( metrics_request_flag & V_TET_ASPECT_FROBENIUS )
1125 [ + - ]: 22 : metric_vals->aspect_frobenius = v_tet_aspect_frobenius( 4, coordinates );
1126 : :
1127 [ + - ][ + - ]: 22 : if( metrics_request_flag & V_TET_MINIMUM_ANGLE ) metric_vals->minimum_angle = v_tet_minimum_angle( 4, coordinates );
1128 : :
1129 [ + - ]: 22 : if( metrics_request_flag & V_TET_COLLAPSE_RATIO )
1130 [ + - ]: 22 : metric_vals->collapse_ratio = v_tet_collapse_ratio( 4, coordinates );
1131 : :
1132 [ + - ][ + - ]: 22 : if( metrics_request_flag & V_TET_RADIUS_RATIO ) metric_vals->radius_ratio = v_tet_radius_ratio( 4, coordinates );
1133 : 22 : }
|