![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /*=========================================================================
00002
00003 Module: $RCSfile: V_TetMetric.cpp,v $
00004
00005 Copyright (c) 2006 Sandia Corporation.
00006 All rights reserved.
00007 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
00008
00009 This software is distributed WITHOUT ANY WARRANTY; without even
00010 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00011 PURPOSE. See the above copyright notice for more information.
00012
00013 =========================================================================*/
00014
00015 /*
00016 *
00017 * TetMetric.cpp contains quality calculations for Tets
00018 *
00019 * This file is part of VERDICT
00020 *
00021 */
00022
00023 #define VERDICT_EXPORTS
00024
00025 #include "moab/verdict.h"
00026 #include "verdict_defines.hpp"
00027 #include "VerdictVector.hpp"
00028 #include "V_GaussIntegration.hpp"
00029 #include
00030
00031 //! the average volume of a tet
00032 double verdict_tet_size = 0;
00033
00034 /*!
00035 set the average volume of a tet
00036 */
00037 C_FUNC_DEF void v_set_tet_size( double size )
00038 {
00039 verdict_tet_size = size;
00040 }
00041
00042 /*!
00043 get the weights based on the average size
00044 of a tet
00045 */
00046 int get_weight( VerdictVector& w1, VerdictVector& w2, VerdictVector& w3 )
00047 {
00048 static const double rt3 = sqrt( 3.0 );
00049 static const double root_of_2 = sqrt( 2.0 );
00050
00051 w1.set( 1, 0, 0 );
00052 w2.set( 0.5, 0.5 * rt3, 0 );
00053 w3.set( 0.5, rt3 / 6.0, root_of_2 / rt3 );
00054
00055 double scale = pow( 6. * verdict_tet_size / determinant( w1, w2, w3 ), 0.3333333333333 );
00056
00057 w1 *= scale;
00058 w2 *= scale;
00059 w3 *= scale;
00060
00061 return 1;
00062 }
00063
00064 /*!
00065 the edge ratio of a tet
00066
00067 NB (P. Pebay 01/22/07):
00068 Hmax / Hmin where Hmax and Hmin are respectively the maximum and the
00069 minimum edge lengths
00070 */
00071 C_FUNC_DEF double v_tet_edge_ratio( int /*num_nodes*/, double coordinates[][3] )
00072 {
00073 VerdictVector a, b, c, d, e, f;
00074
00075 a.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00076 coordinates[1][2] - coordinates[0][2] );
00077
00078 b.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00079 coordinates[2][2] - coordinates[1][2] );
00080
00081 c.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00082 coordinates[0][2] - coordinates[2][2] );
00083
00084 d.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00085 coordinates[3][2] - coordinates[0][2] );
00086
00087 e.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
00088 coordinates[3][2] - coordinates[1][2] );
00089
00090 f.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00091 coordinates[3][2] - coordinates[2][2] );
00092
00093 double a2 = a.length_squared();
00094 double b2 = b.length_squared();
00095 double c2 = c.length_squared();
00096 double d2 = d.length_squared();
00097 double e2 = e.length_squared();
00098 double f2 = f.length_squared();
00099
00100 double m2, M2, mab, mcd, mef, Mab, Mcd, Mef;
00101
00102 if( a2 < b2 )
00103 {
00104 mab = a2;
00105 Mab = b2;
00106 }
00107 else // b2 <= a2
00108 {
00109 mab = b2;
00110 Mab = a2;
00111 }
00112 if( c2 < d2 )
00113 {
00114 mcd = c2;
00115 Mcd = d2;
00116 }
00117 else // d2 <= c2
00118 {
00119 mcd = d2;
00120 Mcd = c2;
00121 }
00122 if( e2 < f2 )
00123 {
00124 mef = e2;
00125 Mef = f2;
00126 }
00127 else // f2 <= e2
00128 {
00129 mef = f2;
00130 Mef = e2;
00131 }
00132
00133 m2 = mab < mcd ? mab : mcd;
00134 m2 = m2 < mef ? m2 : mef;
00135
00136 if( m2 < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
00137
00138 M2 = Mab > Mcd ? Mab : Mcd;
00139 M2 = M2 > Mef ? M2 : Mef;
00140
00141 double edge_ratio = sqrt( M2 / m2 );
00142
00143 if( edge_ratio > 0 ) return (double)VERDICT_MIN( edge_ratio, VERDICT_DBL_MAX );
00144 return (double)VERDICT_MAX( edge_ratio, -VERDICT_DBL_MAX );
00145 }
00146
00147 /*!
00148 the scaled jacobian of a tet
00149
00150 minimum of the jacobian divided by the lengths of 3 edge vectors
00151
00152 */
00153 C_FUNC_DEF double v_tet_scaled_jacobian( int /*num_nodes*/, double coordinates[][3] )
00154 {
00155
00156 VerdictVector side0, side1, side2, side3, side4, side5;
00157
00158 side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00159 coordinates[1][2] - coordinates[0][2] );
00160
00161 side1.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00162 coordinates[2][2] - coordinates[1][2] );
00163
00164 side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00165 coordinates[0][2] - coordinates[2][2] );
00166
00167 side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00168 coordinates[3][2] - coordinates[0][2] );
00169
00170 side4.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
00171 coordinates[3][2] - coordinates[1][2] );
00172
00173 side5.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00174 coordinates[3][2] - coordinates[2][2] );
00175
00176 double jacobi;
00177
00178 jacobi = side3 % ( side2 * side0 );
00179
00180 // products of lengths squared of each edge attached to a node.
00181 double length_squared[4] = { side0.length_squared() * side2.length_squared() * side3.length_squared(),
00182 side0.length_squared() * side1.length_squared() * side4.length_squared(),
00183 side1.length_squared() * side2.length_squared() * side5.length_squared(),
00184 side3.length_squared() * side4.length_squared() * side5.length_squared() };
00185 int which_node = 0;
00186 if( length_squared[1] > length_squared[which_node] ) which_node = 1;
00187 if( length_squared[2] > length_squared[which_node] ) which_node = 2;
00188 if( length_squared[3] > length_squared[which_node] ) which_node = 3;
00189
00190 double length_product = sqrt( length_squared[which_node] );
00191 if( length_product < fabs( jacobi ) ) length_product = fabs( jacobi );
00192
00193 if( length_product < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
00194
00195 static const double root_of_2 = sqrt( 2.0 );
00196
00197 return (double)( root_of_2 * jacobi / length_product );
00198 }
00199
00200 /*!
00201 The radius ratio of a tet
00202
00203 NB (P. Pebay 04/16/07):
00204 CR / (3.0 * IR) where CR is the circumsphere radius and IR is the inscribed
00205 sphere radius.
00206 Note that this metric is similar to the aspect beta of a tet, except that
00207 it does not return VERDICT_DBL_MAX if the element has negative orientation.
00208 */
00209 C_FUNC_DEF double v_tet_radius_ratio( int /*num_nodes*/, double coordinates[][3] )
00210 {
00211
00212 // Determine side vectors
00213 VerdictVector side[6];
00214
00215 side[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00216 coordinates[1][2] - coordinates[0][2] );
00217
00218 side[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00219 coordinates[2][2] - coordinates[1][2] );
00220
00221 side[2].set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00222 coordinates[0][2] - coordinates[2][2] );
00223
00224 side[3].set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00225 coordinates[3][2] - coordinates[0][2] );
00226
00227 side[4].set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
00228 coordinates[3][2] - coordinates[1][2] );
00229
00230 side[5].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00231 coordinates[3][2] - coordinates[2][2] );
00232
00233 VerdictVector numerator = side[3].length_squared() * ( side[2] * side[0] ) +
00234 side[2].length_squared() * ( side[3] * side[0] ) +
00235 side[0].length_squared() * ( side[3] * side[2] );
00236
00237 double area_sum;
00238 area_sum = ( ( side[2] * side[0] ).length() + ( side[3] * side[0] ).length() + ( side[4] * side[1] ).length() +
00239 ( side[3] * side[2] ).length() ) *
00240 0.5;
00241
00242 double volume = v_tet_volume( 4, coordinates );
00243
00244 if( fabs( volume ) < VERDICT_DBL_MIN )
00245 return (double)VERDICT_DBL_MAX;
00246 else
00247 {
00248 double radius_ratio;
00249 radius_ratio = numerator.length() * area_sum / ( 108 * volume * volume );
00250
00251 return (double)VERDICT_MIN( radius_ratio, VERDICT_DBL_MAX );
00252 }
00253 }
00254
00255 /*!
00256 The radius ratio of a positively-oriented tet, a.k.a. "aspect beta"
00257
00258 NB (P. Pebay 04/16/07):
00259 CR / (3.0 * IR) where CR is the circumsphere radius and IR is the inscribed
00260 sphere radius if the element has positive orientation.
00261 Note that this metric is similar to the radius ratio of a tet, except that
00262 it returns VERDICT_DBL_MAX if the element has negative orientation.
00263
00264 */
00265 C_FUNC_DEF double v_tet_aspect_beta( int /*num_nodes*/, double coordinates[][3] )
00266 {
00267
00268 // Determine side vectors
00269 VerdictVector side[6];
00270
00271 side[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00272 coordinates[1][2] - coordinates[0][2] );
00273
00274 side[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00275 coordinates[2][2] - coordinates[1][2] );
00276
00277 side[2].set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00278 coordinates[0][2] - coordinates[2][2] );
00279
00280 side[3].set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00281 coordinates[3][2] - coordinates[0][2] );
00282
00283 side[4].set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
00284 coordinates[3][2] - coordinates[1][2] );
00285
00286 side[5].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00287 coordinates[3][2] - coordinates[2][2] );
00288
00289 VerdictVector numerator = side[3].length_squared() * ( side[2] * side[0] ) +
00290 side[2].length_squared() * ( side[3] * side[0] ) +
00291 side[0].length_squared() * ( side[3] * side[2] );
00292
00293 double area_sum;
00294 area_sum = ( ( side[2] * side[0] ).length() + ( side[3] * side[0] ).length() + ( side[4] * side[1] ).length() +
00295 ( side[3] * side[2] ).length() ) *
00296 0.5;
00297
00298 double volume = v_tet_volume( 4, coordinates );
00299
00300 if( volume < VERDICT_DBL_MIN )
00301 return (double)VERDICT_DBL_MAX;
00302 else
00303 {
00304 double radius_ratio;
00305 radius_ratio = numerator.length() * area_sum / ( 108 * volume * volume );
00306
00307 return (double)VERDICT_MIN( radius_ratio, VERDICT_DBL_MAX );
00308 }
00309 }
00310
00311 /*!
00312 The aspect ratio of a tet
00313
00314 NB (P. Pebay 01/22/07):
00315 Hmax / (2 sqrt(6) r) where Hmax and r respectively denote the greatest edge
00316 length and the inradius of the tetrahedron
00317 */
00318 C_FUNC_DEF double v_tet_aspect_ratio( int /*num_nodes*/, double coordinates[][3] )
00319 {
00320 static const double normal_coeff = sqrt( 6. ) / 12.;
00321
00322 // Determine side vectors
00323 VerdictVector ab, bc, ac, ad, bd, cd;
00324
00325 ab.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00326 coordinates[1][2] - coordinates[0][2] );
00327
00328 ac.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00329 coordinates[2][2] - coordinates[0][2] );
00330
00331 ad.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00332 coordinates[3][2] - coordinates[0][2] );
00333
00334 double detTet = ab % ( ac * ad );
00335
00336 if( detTet < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
00337
00338 bc.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00339 coordinates[2][2] - coordinates[1][2] );
00340
00341 bd.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
00342 coordinates[3][2] - coordinates[1][2] );
00343
00344 cd.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00345 coordinates[3][2] - coordinates[2][2] );
00346
00347 double ab2 = ab.length_squared();
00348 double bc2 = bc.length_squared();
00349 double ac2 = ac.length_squared();
00350 double ad2 = ad.length_squared();
00351 double bd2 = bd.length_squared();
00352 double cd2 = cd.length_squared();
00353
00354 double A = ab2 > bc2 ? ab2 : bc2;
00355 double B = ac2 > ad2 ? ac2 : ad2;
00356 double C = bd2 > cd2 ? bd2 : cd2;
00357 double D = A > B ? A : B;
00358 double hm = D > C ? sqrt( D ) : sqrt( C );
00359
00360 bd = ab * bc;
00361 A = bd.length();
00362 bd = ab * ad;
00363 B = bd.length();
00364 bd = ac * ad;
00365 C = bd.length();
00366 bd = bc * cd;
00367 D = bd.length();
00368
00369 double aspect_ratio;
00370 aspect_ratio = normal_coeff * hm * ( A + B + C + D ) / fabs( detTet );
00371
00372 if( aspect_ratio > 0 ) return (double)VERDICT_MIN( aspect_ratio, VERDICT_DBL_MAX );
00373 return (double)VERDICT_MAX( aspect_ratio, -VERDICT_DBL_MAX );
00374 }
00375
00376 /*!
00377 the aspect gamma of a tet
00378
00379 srms^3 / (8.48528137423857*V) where srms = sqrt(sum(Si^2)/6), where Si is the edge length
00380 */
00381 C_FUNC_DEF double v_tet_aspect_gamma( int /*num_nodes*/, double coordinates[][3] )
00382 {
00383
00384 // Determine side vectors
00385 VerdictVector side0, side1, side2, side3, side4, side5;
00386
00387 side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00388 coordinates[1][2] - coordinates[0][2] );
00389
00390 side1.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00391 coordinates[2][2] - coordinates[1][2] );
00392
00393 side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00394 coordinates[0][2] - coordinates[2][2] );
00395
00396 side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00397 coordinates[3][2] - coordinates[0][2] );
00398
00399 side4.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
00400 coordinates[3][2] - coordinates[1][2] );
00401
00402 side5.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00403 coordinates[3][2] - coordinates[2][2] );
00404
00405 double volume = fabs( v_tet_volume( 4, coordinates ) );
00406
00407 if( volume < VERDICT_DBL_MIN )
00408 return (double)VERDICT_DBL_MAX;
00409 else
00410 {
00411 double srms = sqrt( ( side0.length_squared() + side1.length_squared() + side2.length_squared() +
00412 side3.length_squared() + side4.length_squared() + side5.length_squared() ) /
00413 6.0 );
00414
00415 double aspect_ratio_gamma = pow( srms, 3 ) / ( 8.48528137423857 * volume );
00416 return (double)aspect_ratio_gamma;
00417 }
00418 }
00419
00420 /*!
00421 The aspect frobenius of a tet
00422
00423 NB (P. Pebay 01/22/07):
00424 Frobenius condition number when the reference element is regular
00425 */
00426 C_FUNC_DEF double v_tet_aspect_frobenius( int /*num_nodes*/, double coordinates[][3] )
00427 {
00428 static const double normal_exp = 1. / 3.;
00429
00430 VerdictVector ab, ac, ad;
00431
00432 ab.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00433 coordinates[1][2] - coordinates[0][2] );
00434
00435 ac.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00436 coordinates[2][2] - coordinates[0][2] );
00437
00438 ad.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00439 coordinates[3][2] - coordinates[0][2] );
00440
00441 double denominator = ab % ( ac * ad );
00442 denominator *= denominator;
00443 denominator *= 2.;
00444 denominator = 3. * pow( denominator, normal_exp );
00445
00446 if( denominator < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
00447
00448 double u[3];
00449 ab.get_xyz( u );
00450 double v[3];
00451 ac.get_xyz( v );
00452 double w[3];
00453 ad.get_xyz( w );
00454
00455 double numerator = u[0] * u[0] + u[1] * u[1] + u[2] * u[2];
00456 numerator += v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
00457 numerator += w[0] * w[0] + w[1] * w[1] + w[2] * w[2];
00458 numerator *= 1.5;
00459 numerator -= v[0] * u[0] + v[1] * u[1] + v[2] * u[2];
00460 numerator -= w[0] * u[0] + w[1] * u[1] + w[2] * u[2];
00461 numerator -= w[0] * v[0] + w[1] * v[1] + w[2] * v[2];
00462
00463 double aspect_frobenius = numerator / denominator;
00464
00465 if( aspect_frobenius > 0 ) return (double)VERDICT_MIN( aspect_frobenius, VERDICT_DBL_MAX );
00466 return (double)VERDICT_MAX( aspect_frobenius, -VERDICT_DBL_MAX );
00467 }
00468
00469 /*!
00470 The minimum angle of a tet
00471
00472 NB (P. Pebay 01/22/07):
00473 minimum nonoriented dihedral angle
00474 */
00475 C_FUNC_DEF double v_tet_minimum_angle( int /*num_nodes*/, double coordinates[][3] )
00476 {
00477 static const double normal_coeff = 180. * .3183098861837906715377675267450287;
00478
00479 // Determine side vectors
00480 VerdictVector ab, bc, ad, cd;
00481
00482 ab.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00483 coordinates[1][2] - coordinates[0][2] );
00484
00485 ad.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00486 coordinates[3][2] - coordinates[0][2] );
00487
00488 bc.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00489 coordinates[2][2] - coordinates[1][2] );
00490
00491 cd.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00492 coordinates[3][2] - coordinates[2][2] );
00493
00494 VerdictVector abc = ab * bc;
00495 double nabc = abc.length();
00496 VerdictVector abd = ab * ad;
00497 double nabd = abd.length();
00498 VerdictVector acd = ad * cd;
00499 double nacd = acd.length();
00500 VerdictVector bcd = bc * cd;
00501 double nbcd = bcd.length();
00502
00503 double alpha = acos( ( abc % abd ) / ( nabc * nabd ) );
00504 double beta = acos( ( abc % acd ) / ( nabc * nacd ) );
00505 double gamma = acos( ( abc % bcd ) / ( nabc * nbcd ) );
00506 double delta = acos( ( abd % acd ) / ( nabd * nacd ) );
00507 double epsilon = acos( ( abd % bcd ) / ( nabd * nbcd ) );
00508 double zeta = acos( ( acd % bcd ) / ( nacd * nbcd ) );
00509
00510 alpha = alpha < beta ? alpha : beta;
00511 alpha = alpha < gamma ? alpha : gamma;
00512 alpha = alpha < delta ? alpha : delta;
00513 alpha = alpha < epsilon ? alpha : epsilon;
00514 alpha = alpha < zeta ? alpha : zeta;
00515 alpha *= normal_coeff;
00516
00517 if( alpha < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
00518
00519 if( alpha > 0 ) return (double)VERDICT_MIN( alpha, VERDICT_DBL_MAX );
00520 return (double)VERDICT_MAX( alpha, -VERDICT_DBL_MAX );
00521 }
00522
00523 /*!
00524 The collapse ratio of a tet
00525 */
00526 C_FUNC_DEF double v_tet_collapse_ratio( int /*num_nodes*/, double coordinates[][3] )
00527 {
00528 // Determine side vectors
00529 VerdictVector e01, e02, e03, e12, e13, e23;
00530
00531 e01.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00532 coordinates[1][2] - coordinates[0][2] );
00533
00534 e02.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00535 coordinates[2][2] - coordinates[0][2] );
00536
00537 e03.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00538 coordinates[3][2] - coordinates[0][2] );
00539
00540 e12.set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00541 coordinates[2][2] - coordinates[1][2] );
00542
00543 e13.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
00544 coordinates[3][2] - coordinates[1][2] );
00545
00546 e23.set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00547 coordinates[3][2] - coordinates[2][2] );
00548
00549 double l[6];
00550 l[0] = e01.length();
00551 l[1] = e02.length();
00552 l[2] = e03.length();
00553 l[3] = e12.length();
00554 l[4] = e13.length();
00555 l[5] = e23.length();
00556
00557 // Find longest edge for each bounding triangle of tetrahedron
00558 double l012 = l[4] > l[0] ? l[4] : l[0];
00559 l012 = l[1] > l012 ? l[1] : l012;
00560 double l031 = l[0] > l[2] ? l[0] : l[2];
00561 l031 = l[3] > l031 ? l[3] : l031;
00562 double l023 = l[2] > l[1] ? l[2] : l[1];
00563 l023 = l[5] > l023 ? l[5] : l023;
00564 double l132 = l[4] > l[3] ? l[4] : l[3];
00565 l132 = l[5] > l132 ? l[5] : l132;
00566
00567 // Compute collapse ratio for each vertex/triangle pair
00568 VerdictVector N;
00569 double h, magN;
00570 double cr;
00571 double crMin;
00572
00573 N = e01 * e02;
00574 magN = N.length();
00575 h = ( e03 % N ) / magN; // height of vertex 3 above 0-1-2
00576 crMin = h / l012; // ratio of height to longest edge of 0-1-2
00577
00578 N = e03 * e01;
00579 magN = N.length();
00580 h = ( e02 % N ) / magN; // height of vertex 2 above 0-3-1
00581 cr = h / l031; // ratio of height to longest edge of 0-3-1
00582 if( cr < crMin ) crMin = cr;
00583
00584 N = e02 * e03;
00585 magN = N.length();
00586 h = ( e01 % N ) / magN; // height of vertex 1 above 0-2-3
00587 cr = h / l023; // ratio of height to longest edge of 0-2-3
00588 if( cr < crMin ) crMin = cr;
00589
00590 N = e12 * e13;
00591 magN = N.length();
00592 h = ( e01 % N ) / magN; // height of vertex 0 above 1-3-2
00593 cr = h / l132; // ratio of height to longest edge of 1-3-2
00594 if( cr < crMin ) crMin = cr;
00595
00596 if( crMin < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
00597 if( crMin > 0 ) return (double)VERDICT_MIN( crMin, VERDICT_DBL_MAX );
00598 return (double)VERDICT_MAX( crMin, -VERDICT_DBL_MAX );
00599 }
00600
00601 /*!
00602 the volume of a tet
00603
00604 1/6 * jacobian at a corner node
00605 */
00606 C_FUNC_DEF double v_tet_volume( int /*num_nodes*/, double coordinates[][3] )
00607 {
00608
00609 // Determine side vectors
00610 VerdictVector side0, side2, side3;
00611
00612 side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00613 coordinates[1][2] - coordinates[0][2] );
00614
00615 side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00616 coordinates[0][2] - coordinates[2][2] );
00617
00618 side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00619 coordinates[3][2] - coordinates[0][2] );
00620
00621 return (double)( ( side3 % ( side2 * side0 ) ) / 6.0 );
00622 }
00623
00624 /*!
00625 the condition of a tet
00626
00627 condition number of the jacobian matrix at any corner
00628 */
00629 C_FUNC_DEF double v_tet_condition( int /*num_nodes*/, double coordinates[][3] )
00630 {
00631
00632 double condition, term1, term2, det;
00633 double rt3 = sqrt( 3.0 );
00634 double rt6 = sqrt( 6.0 );
00635
00636 VerdictVector side0, side2, side3;
00637
00638 side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00639 coordinates[1][2] - coordinates[0][2] );
00640
00641 side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00642 coordinates[0][2] - coordinates[2][2] );
00643
00644 side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00645 coordinates[3][2] - coordinates[0][2] );
00646
00647 VerdictVector c_1, c_2, c_3;
00648
00649 c_1 = side0;
00650 c_2 = ( -2 * side2 - side0 ) / rt3;
00651 c_3 = ( 3 * side3 + side2 - side0 ) / rt6;
00652
00653 term1 = c_1 % c_1 + c_2 % c_2 + c_3 % c_3;
00654 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 );
00655 det = c_1 % ( c_2 * c_3 );
00656
00657 if( det <= VERDICT_DBL_MIN )
00658 return VERDICT_DBL_MAX;
00659 else
00660 condition = sqrt( term1 * term2 ) / ( 3.0 * det );
00661
00662 return (double)condition;
00663 }
00664
00665 /*!
00666 the jacobian of a tet
00667
00668 TODO
00669 */
00670 C_FUNC_DEF double v_tet_jacobian( int /*num_nodes*/, double coordinates[][3] )
00671 {
00672 VerdictVector side0, side2, side3;
00673
00674 side0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00675 coordinates[1][2] - coordinates[0][2] );
00676
00677 side2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00678 coordinates[0][2] - coordinates[2][2] );
00679
00680 side3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00681 coordinates[3][2] - coordinates[0][2] );
00682
00683 return (double)( side3 % ( side2 * side0 ) );
00684 }
00685
00686 /*!
00687 the shape of a tet
00688
00689 3/ condition number of weighted jacobian matrix
00690 */
00691 C_FUNC_DEF double v_tet_shape( int /*num_nodes*/, double coordinates[][3] )
00692 {
00693
00694 static const double two_thirds = 2.0 / 3.0;
00695 static const double root_of_2 = sqrt( 2.0 );
00696
00697 VerdictVector edge0, edge2, edge3;
00698
00699 edge0.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00700 coordinates[1][2] - coordinates[0][2] );
00701
00702 edge2.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00703 coordinates[0][2] - coordinates[2][2] );
00704
00705 edge3.set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00706 coordinates[3][2] - coordinates[0][2] );
00707
00708 double jacobian = edge3 % ( edge2 * edge0 );
00709 if( jacobian < VERDICT_DBL_MIN )
00710 {
00711 return (double)0.0;
00712 }
00713 double num = 3 * pow( root_of_2 * jacobian, two_thirds );
00714 double den =
00715 1.5 * ( edge0 % edge0 + edge2 % edge2 + edge3 % edge3 ) - ( edge0 % -edge2 + -edge2 % edge3 + edge3 % edge0 );
00716
00717 if( den < VERDICT_DBL_MIN ) return (double)0.0;
00718
00719 return (double)VERDICT_MAX( num / den, 0 );
00720 }
00721
00722 /*!
00723 the relative size of a tet
00724
00725 Min(J,1/J), where J is the determinant of the weighted Jacobian matrix
00726 */
00727 C_FUNC_DEF double v_tet_relative_size_squared( int /*num_nodes*/, double coordinates[][3] )
00728 {
00729 double size;
00730 VerdictVector w1, w2, w3;
00731 get_weight( w1, w2, w3 );
00732 double avg_volume = ( w1 % ( w2 * w3 ) ) / 6.0;
00733
00734 double volume = v_tet_volume( 4, coordinates );
00735
00736 if( avg_volume < VERDICT_DBL_MIN )
00737 return 0.0;
00738 else
00739 {
00740 size = volume / avg_volume;
00741 if( size <= VERDICT_DBL_MIN ) return 0.0;
00742 if( size > 1 ) size = (double)( 1 ) / size;
00743 }
00744 return (double)( size * size );
00745 }
00746
00747 /*!
00748 the shape and size of a tet
00749
00750 Product of the shape and relative size
00751 */
00752 C_FUNC_DEF double v_tet_shape_and_size( int num_nodes, double coordinates[][3] )
00753 {
00754
00755 double shape, size;
00756 shape = v_tet_shape( num_nodes, coordinates );
00757 size = v_tet_relative_size_squared( num_nodes, coordinates );
00758
00759 return (double)( shape * size );
00760 }
00761
00762 /*!
00763 the distortion of a tet
00764 */
00765 C_FUNC_DEF double v_tet_distortion( int num_nodes, double coordinates[][3] )
00766 {
00767
00768 double distortion = VERDICT_DBL_MAX;
00769 int number_of_gauss_points = 0;
00770 if( num_nodes == 4 )
00771 // for linear tet, the distortion is always 1 because
00772 // straight edge tets are the target shape for tet
00773 return 1.0;
00774
00775 else if( num_nodes == 10 )
00776 // use four integration points for quadratic tet
00777 number_of_gauss_points = 4;
00778
00779 int number_dims = 3;
00780 int total_number_of_gauss_points = number_of_gauss_points;
00781 // use is_tri=1 to indicate this is for tet in 3D
00782 int is_tri = 1;
00783
00784 double shape_function[maxTotalNumberGaussPoints][maxNumberNodes];
00785 double dndy1[maxTotalNumberGaussPoints][maxNumberNodes];
00786 double dndy2[maxTotalNumberGaussPoints][maxNumberNodes];
00787 double dndy3[maxTotalNumberGaussPoints][maxNumberNodes];
00788 double weight[maxTotalNumberGaussPoints];
00789
00790 // create an object of GaussIntegration for tet
00791 GaussIntegration::initialize( number_of_gauss_points, num_nodes, number_dims, is_tri );
00792 GaussIntegration::calculate_shape_function_3d_tet();
00793 GaussIntegration::get_shape_func( shape_function[0], dndy1[0], dndy2[0], dndy3[0], weight );
00794
00795 // vector xxi is the derivative vector of coordinates w.r.t local xi coordinate in the
00796 // computation space
00797 // vector xet is the derivative vector of coordinates w.r.t local et coordinate in the
00798 // computation space
00799 // vector xze is the derivative vector of coordinates w.r.t local ze coordinate in the
00800 // computation space
00801 VerdictVector xxi, xet, xze, xin;
00802
00803 double jacobian, minimum_jacobian;
00804 double element_volume = 0.0;
00805 minimum_jacobian = VERDICT_DBL_MAX;
00806
00807 // calculate element volume
00808 int ife, ja;
00809 for( ife = 0; ife < total_number_of_gauss_points; ife++ )
00810 {
00811 xxi.set( 0.0, 0.0, 0.0 );
00812 xet.set( 0.0, 0.0, 0.0 );
00813 xze.set( 0.0, 0.0, 0.0 );
00814
00815 for( ja = 0; ja < num_nodes; ja++ )
00816 {
00817 xin.set( coordinates[ja][0], coordinates[ja][1], coordinates[ja][2] );
00818 xxi += dndy1[ife][ja] * xin;
00819 xet += dndy2[ife][ja] * xin;
00820 xze += dndy3[ife][ja] * xin;
00821 }
00822
00823 // determinant
00824 jacobian = xxi % ( xet * xze );
00825 if( minimum_jacobian > jacobian ) minimum_jacobian = jacobian;
00826
00827 element_volume += weight[ife] * jacobian;
00828 } // element_volume is 6 times the actual volume
00829
00830 // loop through all nodes
00831 double dndy1_at_node[maxNumberNodes][maxNumberNodes];
00832 double dndy2_at_node[maxNumberNodes][maxNumberNodes];
00833 double dndy3_at_node[maxNumberNodes][maxNumberNodes];
00834
00835 GaussIntegration::calculate_derivative_at_nodes_3d_tet( dndy1_at_node, dndy2_at_node, dndy3_at_node );
00836 int node_id;
00837 for( node_id = 0; node_id < num_nodes; node_id++ )
00838 {
00839 xxi.set( 0.0, 0.0, 0.0 );
00840 xet.set( 0.0, 0.0, 0.0 );
00841 xze.set( 0.0, 0.0, 0.0 );
00842
00843 for( ja = 0; ja < num_nodes; ja++ )
00844 {
00845 xin.set( coordinates[ja][0], coordinates[ja][1], coordinates[ja][2] );
00846 xxi += dndy1_at_node[node_id][ja] * xin;
00847 xet += dndy2_at_node[node_id][ja] * xin;
00848 xze += dndy3_at_node[node_id][ja] * xin;
00849 }
00850
00851 jacobian = xxi % ( xet * xze );
00852 if( minimum_jacobian > jacobian ) minimum_jacobian = jacobian;
00853 }
00854 distortion = minimum_jacobian / element_volume;
00855
00856 return (double)distortion;
00857 }
00858
00859 /*!
00860 the quality metrics of a tet
00861 */
00862 C_FUNC_DEF void v_tet_quality( int num_nodes,
00863 double coordinates[][3],
00864 unsigned int metrics_request_flag,
00865 TetMetricVals* metric_vals )
00866 {
00867
00868 memset( metric_vals, 0, sizeof( TetMetricVals ) );
00869
00870 /*
00871
00872 node numbers and edge numbers below
00873
00874
00875
00876 3
00877 + edge 0 is node 0 to 1
00878 +|+ edge 1 is node 1 to 2
00879 3/ | \5 edge 2 is node 0 to 2
00880 / 4| \ edge 3 is node 0 to 3
00881 0 - -|- + 2 edge 4 is node 1 to 3
00882 \ | + edge 5 is node 2 to 3
00883 0\ | /1
00884 +|/ edge 2 is behind edge 4
00885 1
00886
00887
00888 */
00889
00890 // lets start with making the vectors
00891 VerdictVector edges[6];
00892 edges[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00893 coordinates[1][2] - coordinates[0][2] );
00894
00895 edges[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00896 coordinates[2][2] - coordinates[1][2] );
00897
00898 edges[2].set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00899 coordinates[0][2] - coordinates[2][2] );
00900
00901 edges[3].set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1],
00902 coordinates[3][2] - coordinates[0][2] );
00903
00904 edges[4].set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1],
00905 coordinates[3][2] - coordinates[1][2] );
00906
00907 edges[5].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1],
00908 coordinates[3][2] - coordinates[2][2] );
00909
00910 // common numbers
00911 static const double root_of_2 = sqrt( 2.0 );
00912
00913 // calculate the jacobian
00914 static const int do_jacobian = V_TET_JACOBIAN | V_TET_VOLUME | V_TET_ASPECT_BETA | V_TET_ASPECT_GAMMA |
00915 V_TET_SHAPE | V_TET_RELATIVE_SIZE_SQUARED | V_TET_SHAPE_AND_SIZE |
00916 V_TET_SCALED_JACOBIAN | V_TET_CONDITION;
00917 if( metrics_request_flag & do_jacobian )
00918 {
00919 metric_vals->jacobian = (double)( edges[3] % ( edges[2] * edges[0] ) );
00920 }
00921
00922 // calculate the volume
00923 if( metrics_request_flag & V_TET_VOLUME )
00924 {
00925 metric_vals->volume = (double)( metric_vals->jacobian / 6.0 );
00926 }
00927
00928 // calculate aspect ratio
00929 if( metrics_request_flag & V_TET_ASPECT_BETA )
00930 {
00931 double surface_area = ( ( edges[2] * edges[0] ).length() + ( edges[3] * edges[0] ).length() +
00932 ( edges[4] * edges[1] ).length() + ( edges[3] * edges[2] ).length() ) *
00933 0.5;
00934
00935 VerdictVector numerator = edges[3].length_squared() * ( edges[2] * edges[0] ) +
00936 edges[2].length_squared() * ( edges[3] * edges[0] ) +
00937 edges[0].length_squared() * ( edges[3] * edges[2] );
00938
00939 double volume = metric_vals->jacobian / 6.0;
00940
00941 if( volume < VERDICT_DBL_MIN )
00942 metric_vals->aspect_beta = (double)( VERDICT_DBL_MAX );
00943 else
00944 metric_vals->aspect_beta = (double)( numerator.length() * surface_area / ( 108 * volume * volume ) );
00945 }
00946
00947 // calculate the aspect gamma
00948 if( metrics_request_flag & V_TET_ASPECT_GAMMA )
00949 {
00950 double volume = fabs( metric_vals->jacobian / 6.0 );
00951 if( fabs( volume ) < VERDICT_DBL_MIN )
00952 metric_vals->aspect_gamma = VERDICT_DBL_MAX;
00953 else
00954 {
00955 double srms = sqrt( ( edges[0].length_squared() + edges[1].length_squared() + edges[2].length_squared() +
00956 edges[3].length_squared() + edges[4].length_squared() + edges[5].length_squared() ) /
00957 6.0 );
00958
00959 // cube the srms
00960 srms *= ( srms * srms );
00961 metric_vals->aspect_gamma = (double)( srms / ( 8.48528137423857 * volume ) );
00962 }
00963 }
00964
00965 // calculate the shape of the tet
00966 if( metrics_request_flag & ( V_TET_SHAPE | V_TET_SHAPE_AND_SIZE ) )
00967 {
00968 // if the jacobian is non-positive, the shape is 0
00969 if( metric_vals->jacobian < VERDICT_DBL_MIN )
00970 {
00971 metric_vals->shape = (double)0.0;
00972 }
00973 else
00974 {
00975 static const double two_thirds = 2.0 / 3.0;
00976 double num = 3.0 * pow( root_of_2 * metric_vals->jacobian, two_thirds );
00977 double den = 1.5 * ( edges[0] % edges[0] + edges[2] % edges[2] + edges[3] % edges[3] ) -
00978 ( edges[0] % -edges[2] + -edges[2] % edges[3] + edges[3] % edges[0] );
00979
00980 if( den < VERDICT_DBL_MIN )
00981 metric_vals->shape = (double)0.0;
00982 else
00983 metric_vals->shape = (double)VERDICT_MAX( num / den, 0 );
00984 }
00985 }
00986
00987 // calculate the relative size of the tet
00988 if( metrics_request_flag & ( V_TET_RELATIVE_SIZE_SQUARED | V_TET_SHAPE_AND_SIZE ) )
00989 {
00990 VerdictVector w1, w2, w3;
00991 get_weight( w1, w2, w3 );
00992 double avg_vol = ( w1 % ( w2 * w3 ) ) / 6;
00993
00994 if( avg_vol < VERDICT_DBL_MIN )
00995 metric_vals->relative_size_squared = 0.0;
00996 else
00997 {
00998 double tmp = metric_vals->jacobian / ( 6 * avg_vol );
00999 if( tmp < VERDICT_DBL_MIN )
01000 metric_vals->relative_size_squared = 0.0;
01001 else
01002 {
01003 tmp *= tmp;
01004 metric_vals->relative_size_squared = (double)VERDICT_MIN( tmp, 1 / tmp );
01005 }
01006 }
01007 }
01008
01009 // calculate the shape and size
01010 if( metrics_request_flag & V_TET_SHAPE_AND_SIZE )
01011 {
01012 metric_vals->shape_and_size = (double)( metric_vals->shape * metric_vals->relative_size_squared );
01013 }
01014
01015 // calculate the scaled jacobian
01016 if( metrics_request_flag & V_TET_SCALED_JACOBIAN )
01017 {
01018 // find out which node the normalized jacobian can be calculated at
01019 // and it will be the smaller than at other nodes
01020 double length_squared[4] = { edges[0].length_squared() * edges[2].length_squared() * edges[3].length_squared(),
01021 edges[0].length_squared() * edges[1].length_squared() * edges[4].length_squared(),
01022 edges[1].length_squared() * edges[2].length_squared() * edges[5].length_squared(),
01023 edges[3].length_squared() * edges[4].length_squared() *
01024 edges[5].length_squared() };
01025
01026 int which_node = 0;
01027 if( length_squared[1] > length_squared[which_node] ) which_node = 1;
01028 if( length_squared[2] > length_squared[which_node] ) which_node = 2;
01029 if( length_squared[3] > length_squared[which_node] ) which_node = 3;
01030
01031 // find the scaled jacobian at this node
01032 double length_product = sqrt( length_squared[which_node] );
01033 if( length_product < fabs( metric_vals->jacobian ) ) length_product = fabs( metric_vals->jacobian );
01034
01035 if( length_product < VERDICT_DBL_MIN )
01036 metric_vals->scaled_jacobian = (double)VERDICT_DBL_MAX;
01037 else
01038 metric_vals->scaled_jacobian = (double)( root_of_2 * metric_vals->jacobian / length_product );
01039 }
01040
01041 // calculate the condition number
01042 if( metrics_request_flag & V_TET_CONDITION )
01043 {
01044 static const double root_of_3 = sqrt( 3.0 );
01045 static const double root_of_6 = sqrt( 6.0 );
01046
01047 VerdictVector c_1, c_2, c_3;
01048 c_1 = edges[0];
01049 c_2 = ( -2 * edges[2] - edges[0] ) / root_of_3;
01050 c_3 = ( 3 * edges[3] + edges[2] - edges[0] ) / root_of_6;
01051
01052 double term1 = c_1 % c_1 + c_2 % c_2 + c_3 % c_3;
01053 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 );
01054
01055 double det = c_1 % ( c_2 * c_3 );
01056
01057 if( det <= VERDICT_DBL_MIN )
01058 metric_vals->condition = (double)VERDICT_DBL_MAX;
01059 else
01060 metric_vals->condition = (double)( sqrt( term1 * term2 ) / ( 3.0 * det ) );
01061 }
01062
01063 // calculate the distortion
01064 if( metrics_request_flag & V_TET_DISTORTION )
01065 {
01066 metric_vals->distortion = v_tet_distortion( num_nodes, coordinates );
01067 }
01068
01069 // check for overflow
01070 if( metrics_request_flag & V_TET_ASPECT_BETA )
01071 {
01072 if( metric_vals->aspect_beta > 0 )
01073 metric_vals->aspect_beta = (double)VERDICT_MIN( metric_vals->aspect_beta, VERDICT_DBL_MAX );
01074 metric_vals->aspect_beta = (double)VERDICT_MAX( metric_vals->aspect_beta, -VERDICT_DBL_MAX );
01075 }
01076
01077 if( metrics_request_flag & V_TET_ASPECT_GAMMA )
01078 {
01079 if( metric_vals->aspect_gamma > 0 )
01080 metric_vals->aspect_gamma = (double)VERDICT_MIN( metric_vals->aspect_gamma, VERDICT_DBL_MAX );
01081 metric_vals->aspect_gamma = (double)VERDICT_MAX( metric_vals->aspect_gamma, -VERDICT_DBL_MAX );
01082 }
01083
01084 if( metrics_request_flag & V_TET_VOLUME )
01085 {
01086 if( metric_vals->volume > 0 ) metric_vals->volume = (double)VERDICT_MIN( metric_vals->volume, VERDICT_DBL_MAX );
01087 metric_vals->volume = (double)VERDICT_MAX( metric_vals->volume, -VERDICT_DBL_MAX );
01088 }
01089
01090 if( metrics_request_flag & V_TET_CONDITION )
01091 {
01092 if( metric_vals->condition > 0 )
01093 metric_vals->condition = (double)VERDICT_MIN( metric_vals->condition, VERDICT_DBL_MAX );
01094 metric_vals->condition = (double)VERDICT_MAX( metric_vals->condition, -VERDICT_DBL_MAX );
01095 }
01096
01097 if( metrics_request_flag & V_TET_JACOBIAN )
01098 {
01099 if( metric_vals->jacobian > 0 )
01100 metric_vals->jacobian = (double)VERDICT_MIN( metric_vals->jacobian, VERDICT_DBL_MAX );
01101 metric_vals->jacobian = (double)VERDICT_MAX( metric_vals->jacobian, -VERDICT_DBL_MAX );
01102 }
01103
01104 if( metrics_request_flag & V_TET_SCALED_JACOBIAN )
01105 {
01106 if( metric_vals->scaled_jacobian > 0 )
01107 metric_vals->scaled_jacobian = (double)VERDICT_MIN( metric_vals->scaled_jacobian, VERDICT_DBL_MAX );
01108 metric_vals->scaled_jacobian = (double)VERDICT_MAX( metric_vals->scaled_jacobian, -VERDICT_DBL_MAX );
01109 }
01110
01111 if( metrics_request_flag & V_TET_SHAPE )
01112 {
01113 if( metric_vals->shape > 0 ) metric_vals->shape = (double)VERDICT_MIN( metric_vals->shape, VERDICT_DBL_MAX );
01114 metric_vals->shape = (double)VERDICT_MAX( metric_vals->shape, -VERDICT_DBL_MAX );
01115 }
01116
01117 if( metrics_request_flag & V_TET_RELATIVE_SIZE_SQUARED )
01118 {
01119 if( metric_vals->relative_size_squared > 0 )
01120 metric_vals->relative_size_squared =
01121 (double)VERDICT_MIN( metric_vals->relative_size_squared, VERDICT_DBL_MAX );
01122 metric_vals->relative_size_squared =
01123 (double)VERDICT_MAX( metric_vals->relative_size_squared, -VERDICT_DBL_MAX );
01124 }
01125
01126 if( metrics_request_flag & V_TET_SHAPE_AND_SIZE )
01127 {
01128 if( metric_vals->shape_and_size > 0 )
01129 metric_vals->shape_and_size = (double)VERDICT_MIN( metric_vals->shape_and_size, VERDICT_DBL_MAX );
01130 metric_vals->shape_and_size = (double)VERDICT_MAX( metric_vals->shape_and_size, -VERDICT_DBL_MAX );
01131 }
01132
01133 if( metrics_request_flag & V_TET_DISTORTION )
01134 {
01135 if( metric_vals->distortion > 0 )
01136 metric_vals->distortion = (double)VERDICT_MIN( metric_vals->distortion, VERDICT_DBL_MAX );
01137 metric_vals->distortion = (double)VERDICT_MAX( metric_vals->distortion, -VERDICT_DBL_MAX );
01138 }
01139
01140 if( metrics_request_flag & V_TET_ASPECT_RATIO ) metric_vals->aspect_ratio = v_tet_aspect_ratio( 4, coordinates );
01141
01142 if( metrics_request_flag & V_TET_ASPECT_FROBENIUS )
01143 metric_vals->aspect_frobenius = v_tet_aspect_frobenius( 4, coordinates );
01144
01145 if( metrics_request_flag & V_TET_MINIMUM_ANGLE ) metric_vals->minimum_angle = v_tet_minimum_angle( 4, coordinates );
01146
01147 if( metrics_request_flag & V_TET_COLLAPSE_RATIO )
01148 metric_vals->collapse_ratio = v_tet_collapse_ratio( 4, coordinates );
01149
01150 if( metrics_request_flag & V_TET_RADIUS_RATIO ) metric_vals->radius_ratio = v_tet_radius_ratio( 4, coordinates );
01151 }