MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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 <memory.h> 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 }