![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /*=========================================================================
00002
00003 Module: $RCSfile: V_TriMetric.cpp,v $
00004
00005 Copyright (c) 2007 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 * TriMetric.cpp contains quality calculations for Tris
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 "V_GaussIntegration.hpp"
00028 #include "VerdictVector.hpp"
00029 #include
00030 #include
00031
00032 // the average area of a tri
00033 static double verdict_tri_size = 0;
00034 static ComputeNormal compute_normal = NULL;
00035
00036 /*!
00037 get weights based on the average area of a set of
00038 tris
00039 */
00040 static int v_tri_get_weight( double& m11, double& m21, double& m12, double& m22 )
00041 {
00042 static const double rootOf3 = sqrt( 3.0 );
00043 m11 = 1;
00044 m21 = 0;
00045 m12 = 0.5;
00046 m22 = 0.5 * rootOf3;
00047 double scale = sqrt( 2.0 * verdict_tri_size / ( m11 * m22 - m21 * m12 ) );
00048
00049 m11 *= scale;
00050 m21 *= scale;
00051 m12 *= scale;
00052 m22 *= scale;
00053
00054 return 1;
00055 }
00056
00057 /*! sets the average area of a tri */
00058 C_FUNC_DEF void v_set_tri_size( double size )
00059 {
00060 verdict_tri_size = size;
00061 }
00062
00063 C_FUNC_DEF void v_set_tri_normal_func( ComputeNormal func )
00064 {
00065 compute_normal = func;
00066 }
00067
00068 /*!
00069 the edge ratio of a triangle
00070
00071 NB (P. Pebay 01/14/07):
00072 Hmax / Hmin where Hmax and Hmin are respectively the maximum and the
00073 minimum edge lengths
00074
00075 */
00076 C_FUNC_DEF double v_tri_edge_ratio( int /*num_nodes*/, double coordinates[][3] )
00077 {
00078
00079 // three vectors for each side
00080 VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00081 coordinates[1][2] - coordinates[0][2] );
00082
00083 VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00084 coordinates[2][2] - coordinates[1][2] );
00085
00086 VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00087 coordinates[0][2] - coordinates[2][2] );
00088
00089 double a2 = a.length_squared();
00090 double b2 = b.length_squared();
00091 double c2 = c.length_squared();
00092
00093 double m2, M2;
00094 if( a2 < b2 )
00095 {
00096 if( b2 < c2 )
00097 {
00098 m2 = a2;
00099 M2 = c2;
00100 }
00101 else // b2 <= a2
00102 {
00103 if( a2 < c2 )
00104 {
00105 m2 = a2;
00106 M2 = b2;
00107 }
00108 else // c2 <= a2
00109 {
00110 m2 = c2;
00111 M2 = b2;
00112 }
00113 }
00114 }
00115 else // b2 <= a2
00116 {
00117 if( a2 < c2 )
00118 {
00119 m2 = b2;
00120 M2 = c2;
00121 }
00122 else // c2 <= a2
00123 {
00124 if( b2 < c2 )
00125 {
00126 m2 = b2;
00127 M2 = a2;
00128 }
00129 else // c2 <= b2
00130 {
00131 m2 = c2;
00132 M2 = a2;
00133 }
00134 }
00135 }
00136
00137 if( m2 < VERDICT_DBL_MIN )
00138 return (double)VERDICT_DBL_MAX;
00139 else
00140 {
00141 double edge_ratio;
00142 edge_ratio = sqrt( M2 / m2 );
00143
00144 if( edge_ratio > 0 ) return (double)VERDICT_MIN( edge_ratio, VERDICT_DBL_MAX );
00145 return (double)VERDICT_MAX( edge_ratio, -VERDICT_DBL_MAX );
00146 }
00147 }
00148
00149 /*!
00150 the aspect ratio of a triangle
00151
00152 NB (P. Pebay 01/14/07):
00153 Hmax / ( 2.0 * sqrt(3.0) * IR) where Hmax is the maximum edge length
00154 and IR is the inradius
00155
00156 note that previous incarnations of verdict used "v_tri_aspect_ratio" to denote
00157 what is now called "v_tri_aspect_frobenius"
00158
00159 */
00160 C_FUNC_DEF double v_tri_aspect_ratio( int /*num_nodes*/, double coordinates[][3] )
00161 {
00162 static const double normal_coeff = sqrt( 3. ) / 6.;
00163
00164 // three vectors for each side
00165 VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00166 coordinates[1][2] - coordinates[0][2] );
00167
00168 VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00169 coordinates[2][2] - coordinates[1][2] );
00170
00171 VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00172 coordinates[0][2] - coordinates[2][2] );
00173
00174 double a1 = a.length();
00175 double b1 = b.length();
00176 double c1 = c.length();
00177
00178 double hm = a1 > b1 ? a1 : b1;
00179 hm = hm > c1 ? hm : c1;
00180
00181 VerdictVector ab = a * b;
00182 double denominator = ab.length();
00183
00184 if( denominator < VERDICT_DBL_MIN )
00185 return (double)VERDICT_DBL_MAX;
00186 else
00187 {
00188 double aspect_ratio;
00189 aspect_ratio = normal_coeff * hm * ( a1 + b1 + c1 ) / denominator;
00190
00191 if( aspect_ratio > 0 ) return (double)VERDICT_MIN( aspect_ratio, VERDICT_DBL_MAX );
00192 return (double)VERDICT_MAX( aspect_ratio, -VERDICT_DBL_MAX );
00193 }
00194 }
00195
00196 /*!
00197 the radius ratio of a triangle
00198
00199 NB (P. Pebay 01/13/07):
00200 CR / (3.0*IR) where CR is the circumradius and IR is the inradius
00201
00202 this quality metric is also known to VERDICT, for tetrahedral elements only,
00203 a the "aspect beta"
00204
00205 */
00206 C_FUNC_DEF double v_tri_radius_ratio( int /*num_nodes*/, double coordinates[][3] )
00207 {
00208
00209 // three vectors for each side
00210 VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00211 coordinates[1][2] - coordinates[0][2] );
00212
00213 VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00214 coordinates[2][2] - coordinates[1][2] );
00215
00216 VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00217 coordinates[0][2] - coordinates[2][2] );
00218
00219 double a2 = a.length_squared();
00220 double b2 = b.length_squared();
00221 double c2 = c.length_squared();
00222
00223 VerdictVector ab = a * b;
00224 double denominator = ab.length_squared();
00225
00226 if( denominator < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
00227
00228 double radius_ratio;
00229 radius_ratio = .25 * a2 * b2 * c2 * ( a2 + b2 + c2 ) / denominator;
00230
00231 if( radius_ratio > 0 ) return (double)VERDICT_MIN( radius_ratio, VERDICT_DBL_MAX );
00232 return (double)VERDICT_MAX( radius_ratio, -VERDICT_DBL_MAX );
00233 }
00234
00235 /*!
00236 the Frobenius aspect of a tri
00237
00238 srms^2/(2 * sqrt(3.0) * area)
00239 where srms^2 is sum of the lengths squared
00240
00241 NB (P. Pebay 01/14/07):
00242 this method was called "aspect ratio" in earlier incarnations of VERDICT
00243
00244 */
00245
00246 C_FUNC_DEF double v_tri_aspect_frobenius( int /*num_nodes*/, double coordinates[][3] )
00247 {
00248 static const double two_times_root_of_3 = 2 * sqrt( 3.0 );
00249
00250 // three vectors for each side
00251 VerdictVector side1( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00252 coordinates[1][2] - coordinates[0][2] );
00253
00254 VerdictVector side2( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00255 coordinates[2][2] - coordinates[1][2] );
00256
00257 VerdictVector side3( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00258 coordinates[0][2] - coordinates[2][2] );
00259
00260 // sum the lengths squared of each side
00261 double srms = ( side1.length_squared() + side2.length_squared() + side3.length_squared() );
00262
00263 // find two times the area of the triangle by cross product
00264 double areaX2 = ( ( side1 * ( -side3 ) ).length() );
00265
00266 if( areaX2 == 0.0 ) return (double)VERDICT_DBL_MAX;
00267
00268 double aspect = (double)( srms / ( two_times_root_of_3 * ( areaX2 ) ) );
00269 if( aspect > 0 ) return (double)VERDICT_MIN( aspect, VERDICT_DBL_MAX );
00270 return (double)VERDICT_MAX( aspect, -VERDICT_DBL_MAX );
00271 }
00272
00273 /*!
00274 The area of a tri
00275
00276 0.5 * jacobian at a node
00277 */
00278 C_FUNC_DEF double v_tri_area( int /*num_nodes*/, double coordinates[][3] )
00279 {
00280 // two vectors for two sides
00281 VerdictVector side1( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00282 coordinates[1][2] - coordinates[0][2] );
00283
00284 VerdictVector side3( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00285 coordinates[2][2] - coordinates[0][2] );
00286
00287 // the cross product of the two vectors representing two sides of the
00288 // triangle
00289 VerdictVector tmp = side1 * side3;
00290
00291 // return the magnitude of the vector divided by two
00292 double area = 0.5 * tmp.length();
00293 if( area > 0 ) return (double)VERDICT_MIN( area, VERDICT_DBL_MAX );
00294 return (double)VERDICT_MAX( area, -VERDICT_DBL_MAX );
00295 }
00296
00297 /*!
00298 The minimum angle of a tri
00299
00300 The minimum angle of a tri is the minimum angle between
00301 two adjacents sides out of all three corners of the triangle.
00302 */
00303 C_FUNC_DEF double v_tri_minimum_angle( int /*num_nodes*/, double coordinates[][3] )
00304 {
00305
00306 // vectors for all the sides
00307 VerdictVector sides[4];
00308 sides[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00309 coordinates[1][2] - coordinates[0][2] );
00310 sides[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00311 coordinates[2][2] - coordinates[1][2] );
00312 sides[2].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00313 coordinates[2][2] - coordinates[0][2] );
00314
00315 // in case we need to find the interior angle
00316 // between sides 0 and 1
00317 sides[3] = -sides[1];
00318
00319 // calculate the lengths squared of the sides
00320 double sides_lengths[3];
00321 sides_lengths[0] = sides[0].length_squared();
00322 sides_lengths[1] = sides[1].length_squared();
00323 sides_lengths[2] = sides[2].length_squared();
00324
00325 if( sides_lengths[0] == 0.0 || sides_lengths[1] == 0.0 || sides_lengths[2] == 0.0 ) return 0.0;
00326
00327 // using the law of sines, we know that the minimum
00328 // angle is opposite of the shortest side
00329
00330 // find the shortest side
00331 int short_side = 0;
00332 if( sides_lengths[1] < sides_lengths[0] ) short_side = 1;
00333 if( sides_lengths[2] < sides_lengths[short_side] ) short_side = 2;
00334
00335 // from the shortest side, calculate the angle of the
00336 // opposite angle
00337 double min_angle;
00338 if( short_side == 0 )
00339 {
00340 min_angle = sides[2].interior_angle( sides[1] );
00341 }
00342 else if( short_side == 1 )
00343 {
00344 min_angle = sides[0].interior_angle( sides[2] );
00345 }
00346 else
00347 {
00348 min_angle = sides[0].interior_angle( sides[3] );
00349 }
00350
00351 if( min_angle > 0 ) return (double)VERDICT_MIN( min_angle, VERDICT_DBL_MAX );
00352 return (double)VERDICT_MAX( min_angle, -VERDICT_DBL_MAX );
00353 }
00354
00355 /*!
00356 The maximum angle of a tri
00357
00358 The maximum angle of a tri is the maximum angle between
00359 two adjacents sides out of all three corners of the triangle.
00360 */
00361 C_FUNC_DEF double v_tri_maximum_angle( int /*num_nodes*/, double coordinates[][3] )
00362 {
00363
00364 // vectors for all the sides
00365 VerdictVector sides[4];
00366 sides[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00367 coordinates[1][2] - coordinates[0][2] );
00368 sides[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00369 coordinates[2][2] - coordinates[1][2] );
00370 sides[2].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00371 coordinates[2][2] - coordinates[0][2] );
00372
00373 // in case we need to find the interior angle
00374 // between sides 0 and 1
00375 sides[3] = -sides[1];
00376
00377 // calculate the lengths squared of the sides
00378 double sides_lengths[3];
00379 sides_lengths[0] = sides[0].length_squared();
00380 sides_lengths[1] = sides[1].length_squared();
00381 sides_lengths[2] = sides[2].length_squared();
00382
00383 if( sides_lengths[0] == 0.0 || sides_lengths[1] == 0.0 || sides_lengths[2] == 0.0 )
00384 {
00385 return 0.0;
00386 }
00387
00388 // using the law of sines, we know that the maximum
00389 // angle is opposite of the longest side
00390
00391 // find the longest side
00392 int short_side = 0;
00393 if( sides_lengths[1] > sides_lengths[0] ) short_side = 1;
00394 if( sides_lengths[2] > sides_lengths[short_side] ) short_side = 2;
00395
00396 // from the longest side, calculate the angle of the
00397 // opposite angle
00398 double max_angle;
00399 if( short_side == 0 )
00400 {
00401 max_angle = sides[2].interior_angle( sides[1] );
00402 }
00403 else if( short_side == 1 )
00404 {
00405 max_angle = sides[0].interior_angle( sides[2] );
00406 }
00407 else
00408 {
00409 max_angle = sides[0].interior_angle( sides[3] );
00410 }
00411
00412 if( max_angle > 0 ) return (double)VERDICT_MIN( max_angle, VERDICT_DBL_MAX );
00413 return (double)VERDICT_MAX( max_angle, -VERDICT_DBL_MAX );
00414 }
00415
00416 /*!
00417 The condition of a tri
00418
00419 Condition number of the jacobian matrix at any corner
00420 */
00421 C_FUNC_DEF double v_tri_condition( int /*num_nodes*/, double coordinates[][3] )
00422 {
00423 static const double rt3 = sqrt( 3.0 );
00424
00425 VerdictVector v1( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00426 coordinates[1][2] - coordinates[0][2] );
00427
00428 VerdictVector v2( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00429 coordinates[2][2] - coordinates[0][2] );
00430
00431 VerdictVector tri_normal = v1 * v2;
00432 double areax2 = tri_normal.length();
00433
00434 if( areax2 == 0.0 ) return (double)VERDICT_DBL_MAX;
00435
00436 double condition = (double)( ( ( v1 % v1 ) + ( v2 % v2 ) - ( v1 % v2 ) ) / ( areax2 * rt3 ) );
00437
00438 // check for inverted if we have access to the normal
00439 if( compute_normal )
00440 {
00441 // center of tri
00442 double point[3], surf_normal[3];
00443 point[0] = ( coordinates[0][0] + coordinates[1][0] + coordinates[2][0] ) / 3;
00444 point[1] = ( coordinates[0][1] + coordinates[1][1] + coordinates[2][1] ) / 3;
00445 point[2] = ( coordinates[0][2] + coordinates[1][2] + coordinates[2][2] ) / 3;
00446
00447 // dot product
00448 compute_normal( point, surf_normal );
00449 if( ( tri_normal.x() * surf_normal[0] + tri_normal.y() * surf_normal[1] + tri_normal.z() * surf_normal[2] ) <
00450 0 )
00451 return (double)VERDICT_DBL_MAX;
00452 }
00453 return (double)VERDICT_MIN( condition, VERDICT_DBL_MAX );
00454 }
00455
00456 /*!
00457 The scaled jacobian of a tri
00458
00459 minimum of the jacobian divided by the lengths of 2 edge vectors
00460 */
00461 C_FUNC_DEF double v_tri_scaled_jacobian( int /*num_nodes*/, double coordinates[][3] )
00462 {
00463 static const double detw = 2. / sqrt( 3.0 );
00464 VerdictVector first, second;
00465 double jacobian;
00466
00467 VerdictVector edge[3];
00468 edge[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00469 coordinates[1][2] - coordinates[0][2] );
00470
00471 edge[1].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00472 coordinates[2][2] - coordinates[0][2] );
00473
00474 edge[2].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00475 coordinates[2][2] - coordinates[1][2] );
00476 first = edge[1] - edge[0];
00477 second = edge[2] - edge[0];
00478
00479 VerdictVector cross = first * second;
00480 jacobian = cross.length();
00481
00482 double max_edge_length_product;
00483 max_edge_length_product =
00484 VERDICT_MAX( edge[0].length() * edge[1].length(),
00485 VERDICT_MAX( edge[1].length() * edge[2].length(), edge[0].length() * edge[2].length() ) );
00486
00487 if( max_edge_length_product < VERDICT_DBL_MIN ) return (double)0.0;
00488
00489 jacobian *= detw;
00490 jacobian /= max_edge_length_product;
00491
00492 if( compute_normal )
00493 {
00494 // center of tri
00495 double point[3], surf_normal[3];
00496 point[0] = ( coordinates[0][0] + coordinates[1][0] + coordinates[2][0] ) / 3;
00497 point[1] = ( coordinates[0][1] + coordinates[1][1] + coordinates[2][1] ) / 3;
00498 point[2] = ( coordinates[0][2] + coordinates[1][2] + coordinates[2][2] ) / 3;
00499
00500 // dot product
00501 compute_normal( point, surf_normal );
00502 if( ( cross.x() * surf_normal[0] + cross.y() * surf_normal[1] + cross.z() * surf_normal[2] ) < 0 )
00503 jacobian *= -1;
00504 }
00505
00506 if( jacobian > 0 ) return (double)VERDICT_MIN( jacobian, VERDICT_DBL_MAX );
00507 return (double)VERDICT_MAX( jacobian, -VERDICT_DBL_MAX );
00508 }
00509
00510 /*!
00511 The shape of a tri
00512
00513 2 / condition number of weighted jacobian matrix
00514 */
00515 C_FUNC_DEF double v_tri_shape( int num_nodes, double coordinates[][3] )
00516 {
00517 double condition = v_tri_condition( num_nodes, coordinates );
00518
00519 double shape;
00520 if( condition <= VERDICT_DBL_MIN )
00521 shape = VERDICT_DBL_MAX;
00522 else
00523 shape = ( 1 / condition );
00524
00525 if( shape > 0 ) return (double)VERDICT_MIN( shape, VERDICT_DBL_MAX );
00526 return (double)VERDICT_MAX( shape, -VERDICT_DBL_MAX );
00527 }
00528
00529 /*!
00530 The relative size of a tri
00531
00532 Min(J,1/J) where J is the determinant of the weighted jacobian matrix.
00533 */
00534 C_FUNC_DEF double v_tri_relative_size_squared( int /*num_nodes*/, double coordinates[][3] )
00535 {
00536 double w11, w21, w12, w22;
00537
00538 VerdictVector xxi, xet, tri_normal;
00539
00540 v_tri_get_weight( w11, w21, w12, w22 );
00541
00542 double detw = determinant( w11, w21, w12, w22 );
00543
00544 if( detw == 0.0 ) return 0.0;
00545
00546 xxi.set( coordinates[0][0] - coordinates[1][0], coordinates[0][1] - coordinates[1][1],
00547 coordinates[0][2] - coordinates[1][2] );
00548
00549 xet.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
00550 coordinates[0][2] - coordinates[2][2] );
00551
00552 tri_normal = xxi * xet;
00553
00554 double deta = tri_normal.length();
00555 if( deta == 0.0 || detw == 0.0 ) return 0.0;
00556
00557 double size = pow( deta / detw, 2 );
00558
00559 double rel_size = VERDICT_MIN( size, 1.0 / size );
00560
00561 if( rel_size > 0 ) return (double)VERDICT_MIN( rel_size, VERDICT_DBL_MAX );
00562 return (double)VERDICT_MAX( rel_size, -VERDICT_DBL_MAX );
00563 }
00564
00565 /*!
00566 The shape and size of a tri
00567
00568 Product of the Shape and Relative Size
00569 */
00570 C_FUNC_DEF double v_tri_shape_and_size( int num_nodes, double coordinates[][3] )
00571 {
00572 double size, shape;
00573
00574 size = v_tri_relative_size_squared( num_nodes, coordinates );
00575 shape = v_tri_shape( num_nodes, coordinates );
00576
00577 double shape_and_size = size * shape;
00578
00579 if( shape_and_size > 0 ) return (double)VERDICT_MIN( shape_and_size, VERDICT_DBL_MAX );
00580 return (double)VERDICT_MAX( shape_and_size, -VERDICT_DBL_MAX );
00581 }
00582
00583 /*!
00584 The distortion of a tri
00585
00586 TODO: make a short definition of the distortion and comment below
00587 */
00588 C_FUNC_DEF double v_tri_distortion( int num_nodes, double coordinates[][3] )
00589 {
00590
00591 double distortion;
00592 int total_number_of_gauss_points = 0;
00593 VerdictVector aa, bb, cc, normal_at_point, xin;
00594 double element_area = 0.;
00595
00596 aa.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00597 coordinates[1][2] - coordinates[0][2] );
00598
00599 bb.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00600 coordinates[2][2] - coordinates[0][2] );
00601
00602 VerdictVector tri_normal = aa * bb;
00603
00604 int number_of_gauss_points = 0;
00605 if( num_nodes == 3 )
00606 {
00607 distortion = 1.0;
00608 return (double)distortion;
00609 }
00610
00611 else if( num_nodes == 6 )
00612 {
00613 total_number_of_gauss_points = 6;
00614 number_of_gauss_points = 6;
00615 }
00616
00617 distortion = VERDICT_DBL_MAX;
00618 double shape_function[maxTotalNumberGaussPoints][maxNumberNodes];
00619 double dndy1[maxTotalNumberGaussPoints][maxNumberNodes];
00620 double dndy2[maxTotalNumberGaussPoints][maxNumberNodes];
00621 double weight[maxTotalNumberGaussPoints];
00622
00623 // create an object of GaussIntegration
00624 int number_dims = 2;
00625 int is_tri = 1;
00626 GaussIntegration::initialize( number_of_gauss_points, num_nodes, number_dims, is_tri );
00627 GaussIntegration::calculate_shape_function_2d_tri();
00628 GaussIntegration::get_shape_func( shape_function[0], dndy1[0], dndy2[0], weight );
00629
00630 // calculate element area
00631 int ife, ja;
00632 for( ife = 0; ife < total_number_of_gauss_points; ife++ )
00633 {
00634 aa.set( 0.0, 0.0, 0.0 );
00635 bb.set( 0.0, 0.0, 0.0 );
00636
00637 for( ja = 0; ja < num_nodes; ja++ )
00638 {
00639 xin.set( coordinates[ja][0], coordinates[ja][1], coordinates[ja][2] );
00640 aa += dndy1[ife][ja] * xin;
00641 bb += dndy2[ife][ja] * xin;
00642 }
00643 normal_at_point = aa * bb;
00644 double jacobian = normal_at_point.length();
00645 element_area += weight[ife] * jacobian;
00646 }
00647
00648 element_area *= 0.8660254;
00649 double dndy1_at_node[maxNumberNodes][maxNumberNodes];
00650 double dndy2_at_node[maxNumberNodes][maxNumberNodes];
00651
00652 GaussIntegration::calculate_derivative_at_nodes_2d_tri( dndy1_at_node, dndy2_at_node );
00653
00654 VerdictVector normal_at_nodes[7];
00655
00656 // evaluate normal at nodes and distortion values at nodes
00657 int jai = 0;
00658 for( ja = 0; ja < num_nodes; ja++ )
00659 {
00660 aa.set( 0.0, 0.0, 0.0 );
00661 bb.set( 0.0, 0.0, 0.0 );
00662 for( jai = 0; jai < num_nodes; jai++ )
00663 {
00664 xin.set( coordinates[jai][0], coordinates[jai][1], coordinates[jai][2] );
00665 aa += dndy1_at_node[ja][jai] * xin;
00666 bb += dndy2_at_node[ja][jai] * xin;
00667 }
00668 normal_at_nodes[ja] = aa * bb;
00669 normal_at_nodes[ja].normalize();
00670 }
00671
00672 // determine if element is flat
00673 bool flat_element = true;
00674 double dot_product;
00675
00676 for( ja = 0; ja < num_nodes; ja++ )
00677 {
00678 dot_product = normal_at_nodes[0] % normal_at_nodes[ja];
00679 if( fabs( dot_product ) < 0.99 )
00680 {
00681 flat_element = false;
00682 break;
00683 }
00684 }
00685
00686 // take into consideration of the thickness of the element
00687 double thickness, thickness_gauss;
00688 double distrt;
00689 // get_tri_thickness(tri, element_area, thickness );
00690 thickness = 0.001 * sqrt( element_area );
00691
00692 // set thickness gauss point location
00693 double zl = 0.5773502691896;
00694 if( flat_element ) zl = 0.0;
00695
00696 int no_gauss_pts_z = ( flat_element ) ? 1 : 2;
00697 double thickness_z;
00698
00699 // loop on integration points
00700 int igz;
00701 for( ife = 0; ife < total_number_of_gauss_points; ife++ )
00702 {
00703 // loop on the thickness direction gauss points
00704 for( igz = 0; igz < no_gauss_pts_z; igz++ )
00705 {
00706 zl = -zl;
00707 thickness_z = zl * thickness / 2.0;
00708
00709 aa.set( 0.0, 0.0, 0.0 );
00710 bb.set( 0.0, 0.0, 0.0 );
00711 cc.set( 0.0, 0.0, 0.0 );
00712
00713 for( ja = 0; ja < num_nodes; ja++ )
00714 {
00715 xin.set( coordinates[jai][0], coordinates[jai][1], coordinates[jai][2] );
00716 xin += thickness_z * normal_at_nodes[ja];
00717 aa += dndy1[ife][ja] * xin;
00718 bb += dndy2[ife][ja] * xin;
00719 thickness_gauss = shape_function[ife][ja] * thickness / 2.0;
00720 cc += thickness_gauss * normal_at_nodes[ja];
00721 }
00722
00723 normal_at_point = aa * bb;
00724 distrt = cc % normal_at_point;
00725 if( distrt < distortion ) distortion = distrt;
00726 }
00727 }
00728
00729 // loop through nodal points
00730 for( ja = 0; ja < num_nodes; ja++ )
00731 {
00732 for( igz = 0; igz < no_gauss_pts_z; igz++ )
00733 {
00734 zl = -zl;
00735 thickness_z = zl * thickness / 2.0;
00736
00737 aa.set( 0.0, 0.0, 0.0 );
00738 bb.set( 0.0, 0.0, 0.0 );
00739 cc.set( 0.0, 0.0, 0.0 );
00740
00741 for( jai = 0; jai < num_nodes; jai++ )
00742 {
00743 xin.set( coordinates[jai][0], coordinates[jai][1], coordinates[jai][2] );
00744 xin += thickness_z * normal_at_nodes[ja];
00745 aa += dndy1_at_node[ja][jai] * xin;
00746 bb += dndy2_at_node[ja][jai] * xin;
00747 if( jai == ja )
00748 thickness_gauss = thickness / 2.0;
00749 else
00750 thickness_gauss = 0.;
00751 cc += thickness_gauss * normal_at_nodes[jai];
00752 }
00753 }
00754
00755 normal_at_point = aa * bb;
00756 double sign_jacobian = ( tri_normal % normal_at_point ) > 0 ? 1. : -1.;
00757 distrt = sign_jacobian * ( cc % normal_at_point );
00758
00759 if( distrt < distortion ) distortion = distrt;
00760 }
00761 if( element_area * thickness != 0 )
00762 distortion *= 1. / ( element_area * thickness );
00763 else
00764 distortion *= 1.;
00765
00766 if( distortion > 0 ) return (double)VERDICT_MIN( distortion, VERDICT_DBL_MAX );
00767 return (double)VERDICT_MAX( distortion, -VERDICT_DBL_MAX );
00768 }
00769
00770 /*!
00771 tri_quality for calculating multiple tri metrics at once
00772
00773 using this method is generally faster than using the individual
00774 method multiple times.
00775
00776 */
00777 C_FUNC_DEF void v_tri_quality( int num_nodes,
00778 double coordinates[][3],
00779 unsigned int metrics_request_flag,
00780 TriMetricVals* metric_vals )
00781 {
00782
00783 memset( metric_vals, 0, sizeof( TriMetricVals ) );
00784
00785 // for starts, lets set up some basic and common information
00786
00787 /* node numbers and side numbers used below
00788
00789 2
00790 ++
00791 / \
00792 2 / \ 1
00793 / \
00794 / \
00795 0 ---------+ 1
00796 0
00797 */
00798
00799 // vectors for each side
00800 VerdictVector sides[3];
00801 sides[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
00802 coordinates[1][2] - coordinates[0][2] );
00803 sides[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
00804 coordinates[2][2] - coordinates[1][2] );
00805 sides[2].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
00806 coordinates[2][2] - coordinates[0][2] );
00807 VerdictVector tri_normal = sides[0] * sides[2];
00808 // if we have access to normal information, check to see if the
00809 // element is inverted. If we don't have the normal information
00810 // that we need for this, assume the element is not inverted.
00811 // This flag will be used for condition number, jacobian, shape,
00812 // and size and shape.
00813 bool is_inverted = false;
00814 if( compute_normal )
00815 {
00816 // center of tri
00817 double point[3], surf_normal[3];
00818 point[0] = ( coordinates[0][0] + coordinates[1][0] + coordinates[2][0] ) / 3;
00819 point[1] = ( coordinates[0][1] + coordinates[1][1] + coordinates[2][1] ) / 3;
00820 point[2] = ( coordinates[0][2] + coordinates[1][2] + coordinates[2][2] ) / 3;
00821 // dot product
00822 compute_normal( point, surf_normal );
00823 if( ( tri_normal.x() * surf_normal[0] + tri_normal.y() * surf_normal[1] + tri_normal.z() * surf_normal[2] ) <
00824 0 )
00825 is_inverted = true;
00826 }
00827
00828 // lengths squared of each side
00829 double sides_lengths_squared[3];
00830 sides_lengths_squared[0] = sides[0].length_squared();
00831 sides_lengths_squared[1] = sides[1].length_squared();
00832 sides_lengths_squared[2] = sides[2].length_squared();
00833
00834 // if we are doing angle calcuations
00835 if( metrics_request_flag & ( V_TRI_MINIMUM_ANGLE | V_TRI_MAXIMUM_ANGLE ) )
00836 {
00837 // which is short and long side
00838 int short_side = 0, long_side = 0;
00839
00840 if( sides_lengths_squared[1] < sides_lengths_squared[0] ) short_side = 1;
00841 if( sides_lengths_squared[2] < sides_lengths_squared[short_side] ) short_side = 2;
00842
00843 if( sides_lengths_squared[1] > sides_lengths_squared[0] ) long_side = 1;
00844 if( sides_lengths_squared[2] > sides_lengths_squared[long_side] ) long_side = 2;
00845
00846 // calculate the minimum angle of the tri
00847 if( metrics_request_flag & V_TRI_MINIMUM_ANGLE )
00848 {
00849 if( sides_lengths_squared[0] == 0.0 || sides_lengths_squared[1] == 0.0 || sides_lengths_squared[2] == 0.0 )
00850 {
00851 metric_vals->minimum_angle = 0.0;
00852 }
00853 else if( short_side == 0 )
00854 metric_vals->minimum_angle = (double)sides[2].interior_angle( sides[1] );
00855 else if( short_side == 1 )
00856 metric_vals->minimum_angle = (double)sides[0].interior_angle( sides[2] );
00857 else
00858 metric_vals->minimum_angle = (double)sides[0].interior_angle( -sides[1] );
00859 }
00860
00861 // calculate the maximum angle of the tri
00862 if( metrics_request_flag & V_TRI_MAXIMUM_ANGLE )
00863 {
00864 if( sides_lengths_squared[0] == 0.0 || sides_lengths_squared[1] == 0.0 || sides_lengths_squared[2] == 0.0 )
00865 {
00866 metric_vals->maximum_angle = 0.0;
00867 }
00868 else if( long_side == 0 )
00869 metric_vals->maximum_angle = (double)sides[2].interior_angle( sides[1] );
00870 else if( long_side == 1 )
00871 metric_vals->maximum_angle = (double)sides[0].interior_angle( sides[2] );
00872 else
00873 metric_vals->maximum_angle = (double)sides[0].interior_angle( -sides[1] );
00874 }
00875 }
00876
00877 // calculate the area of the tri
00878 // the following metrics depend on area
00879 if( metrics_request_flag &
00880 ( V_TRI_AREA | V_TRI_SCALED_JACOBIAN | V_TRI_SHAPE | V_TRI_RELATIVE_SIZE_SQUARED | V_TRI_SHAPE_AND_SIZE ) )
00881 {
00882 metric_vals->area = (double)( ( sides[0] * sides[2] ).length() * 0.5 );
00883 }
00884
00885 // calculate the aspect ratio
00886 if( metrics_request_flag & V_TRI_ASPECT_FROBENIUS )
00887 {
00888 // sum the lengths squared
00889 double srms = sides_lengths_squared[0] + sides_lengths_squared[1] + sides_lengths_squared[2];
00890
00891 // calculate once and reuse
00892 static const double twoTimesRootOf3 = 2 * sqrt( 3.0 );
00893
00894 double div = ( twoTimesRootOf3 * ( ( sides[0] * sides[2] ).length() ) );
00895
00896 if( div == 0.0 )
00897 metric_vals->aspect_frobenius = (double)VERDICT_DBL_MAX;
00898 else
00899 metric_vals->aspect_frobenius = (double)( srms / div );
00900 }
00901
00902 // calculate the scaled jacobian
00903 if( metrics_request_flag & V_TRI_SCALED_JACOBIAN )
00904 {
00905 // calculate once and reuse
00906 static const double twoOverRootOf3 = 2 / sqrt( 3.0 );
00907 // use the area from above
00908
00909 double tmp = tri_normal.length() * twoOverRootOf3;
00910
00911 // now scale it by the lengths of the sides
00912 double min_scaled_jac = VERDICT_DBL_MAX;
00913 double temp_scaled_jac;
00914 for( int i = 0; i < 3; i++ )
00915 {
00916 if( sides_lengths_squared[i % 3] == 0.0 || sides_lengths_squared[( i + 2 ) % 3] == 0.0 )
00917 temp_scaled_jac = 0.0;
00918 else
00919 temp_scaled_jac =
00920 tmp / sqrt( sides_lengths_squared[i % 3] ) / sqrt( sides_lengths_squared[( i + 2 ) % 3] );
00921 if( temp_scaled_jac < min_scaled_jac ) min_scaled_jac = temp_scaled_jac;
00922 }
00923 // multiply by -1 if the normals are in opposite directions
00924 if( is_inverted )
00925 {
00926 min_scaled_jac *= -1;
00927 }
00928 metric_vals->scaled_jacobian = (double)min_scaled_jac;
00929 }
00930
00931 // calculate the condition number
00932 if( metrics_request_flag & V_TRI_CONDITION )
00933 {
00934 // calculate once and reuse
00935 static const double rootOf3 = sqrt( 3.0 );
00936 // if it is inverted, the condition number is considered to be infinity.
00937 if( is_inverted )
00938 {
00939 metric_vals->condition = VERDICT_DBL_MAX;
00940 }
00941 else
00942 {
00943 double area2x = ( sides[0] * sides[2] ).length();
00944 if( area2x == 0.0 )
00945 metric_vals->condition = (double)( VERDICT_DBL_MAX );
00946 else
00947 metric_vals->condition = (double)( ( sides[0] % sides[0] + sides[2] % sides[2] - sides[0] % sides[2] ) /
00948 ( area2x * rootOf3 ) );
00949 }
00950 }
00951
00952 // calculate the shape
00953 if( metrics_request_flag & V_TRI_SHAPE || metrics_request_flag & V_TRI_SHAPE_AND_SIZE )
00954 {
00955 // if element is inverted, shape is zero. We don't need to
00956 // calculate anything.
00957 if( is_inverted )
00958 {
00959 metric_vals->shape = 0.0;
00960 }
00961 else
00962 { // otherwise, we calculate the shape
00963 // calculate once and reuse
00964 static const double rootOf3 = sqrt( 3.0 );
00965 // reuse area from before
00966 double area2x = metric_vals->area * 2;
00967 // dot products
00968 double dots[3] = { sides[0] % sides[0], sides[2] % sides[2], sides[0] % sides[2] };
00969
00970 // add the dots
00971 double sum_dots = dots[0] + dots[1] - dots[2];
00972
00973 // then the finale
00974 if( sum_dots == 0.0 )
00975 metric_vals->shape = 0.0;
00976 else
00977 metric_vals->shape = (double)( rootOf3 * area2x / sum_dots );
00978 }
00979 }
00980
00981 // calculate relative size squared
00982 if( metrics_request_flag & V_TRI_RELATIVE_SIZE_SQUARED || metrics_request_flag & V_TRI_SHAPE_AND_SIZE )
00983 {
00984 // get weights
00985 double w11, w21, w12, w22;
00986 v_tri_get_weight( w11, w21, w12, w22 );
00987 // get the determinant
00988 double detw = determinant( w11, w21, w12, w22 );
00989 // use the area from above and divide with the determinant
00990 if( metric_vals->area == 0.0 || detw == 0.0 )
00991 metric_vals->relative_size_squared = 0.0;
00992 else
00993 {
00994 double size = metric_vals->area * 2.0 / detw;
00995 // square the size
00996 size *= size;
00997 // value ranges between 0 to 1
00998 metric_vals->relative_size_squared = (double)VERDICT_MIN( size, 1.0 / size );
00999 }
01000 }
01001
01002 // calculate shape and size
01003 if( metrics_request_flag & V_TRI_SHAPE_AND_SIZE )
01004 {
01005 metric_vals->shape_and_size = metric_vals->relative_size_squared * metric_vals->shape;
01006 }
01007
01008 // calculate distortion
01009 if( metrics_request_flag & V_TRI_DISTORTION ) metric_vals->distortion = v_tri_distortion( num_nodes, coordinates );
01010
01011 // take care of any over-flow problems
01012 if( metric_vals->aspect_frobenius > 0 )
01013 metric_vals->aspect_frobenius = (double)VERDICT_MIN( metric_vals->aspect_frobenius, VERDICT_DBL_MAX );
01014 else
01015 metric_vals->aspect_frobenius = (double)VERDICT_MAX( metric_vals->aspect_frobenius, -VERDICT_DBL_MAX );
01016
01017 if( metric_vals->area > 0 )
01018 metric_vals->area = (double)VERDICT_MIN( metric_vals->area, VERDICT_DBL_MAX );
01019 else
01020 metric_vals->area = (double)VERDICT_MAX( metric_vals->area, -VERDICT_DBL_MAX );
01021
01022 if( metric_vals->minimum_angle > 0 )
01023 metric_vals->minimum_angle = (double)VERDICT_MIN( metric_vals->minimum_angle, VERDICT_DBL_MAX );
01024 else
01025 metric_vals->minimum_angle = (double)VERDICT_MAX( metric_vals->minimum_angle, -VERDICT_DBL_MAX );
01026
01027 if( metric_vals->maximum_angle > 0 )
01028 metric_vals->maximum_angle = (double)VERDICT_MIN( metric_vals->maximum_angle, VERDICT_DBL_MAX );
01029 else
01030 metric_vals->maximum_angle = (double)VERDICT_MAX( metric_vals->maximum_angle, -VERDICT_DBL_MAX );
01031
01032 if( metric_vals->condition > 0 )
01033 metric_vals->condition = (double)VERDICT_MIN( metric_vals->condition, VERDICT_DBL_MAX );
01034 else
01035 metric_vals->condition = (double)VERDICT_MAX( metric_vals->condition, -VERDICT_DBL_MAX );
01036
01037 if( metric_vals->shape > 0 )
01038 metric_vals->shape = (double)VERDICT_MIN( metric_vals->shape, VERDICT_DBL_MAX );
01039 else
01040 metric_vals->shape = (double)VERDICT_MAX( metric_vals->shape, -VERDICT_DBL_MAX );
01041
01042 if( metric_vals->scaled_jacobian > 0 )
01043 metric_vals->scaled_jacobian = (double)VERDICT_MIN( metric_vals->scaled_jacobian, VERDICT_DBL_MAX );
01044 else
01045 metric_vals->scaled_jacobian = (double)VERDICT_MAX( metric_vals->scaled_jacobian, -VERDICT_DBL_MAX );
01046
01047 if( metric_vals->relative_size_squared > 0 )
01048 metric_vals->relative_size_squared = (double)VERDICT_MIN( metric_vals->relative_size_squared, VERDICT_DBL_MAX );
01049 else
01050 metric_vals->relative_size_squared =
01051 (double)VERDICT_MAX( metric_vals->relative_size_squared, -VERDICT_DBL_MAX );
01052
01053 if( metric_vals->shape_and_size > 0 )
01054 metric_vals->shape_and_size = (double)VERDICT_MIN( metric_vals->shape_and_size, VERDICT_DBL_MAX );
01055 else
01056 metric_vals->shape_and_size = (double)VERDICT_MAX( metric_vals->shape_and_size, -VERDICT_DBL_MAX );
01057
01058 if( metric_vals->distortion > 0 )
01059 metric_vals->distortion = (double)VERDICT_MIN( metric_vals->distortion, VERDICT_DBL_MAX );
01060 else
01061 metric_vals->distortion = (double)VERDICT_MAX( metric_vals->distortion, -VERDICT_DBL_MAX );
01062
01063 if( metrics_request_flag & V_TRI_EDGE_RATIO )
01064 {
01065 metric_vals->edge_ratio = v_tri_edge_ratio( 3, coordinates );
01066 }
01067 if( metrics_request_flag & V_TRI_RADIUS_RATIO )
01068 {
01069 metric_vals->radius_ratio = v_tri_radius_ratio( 3, coordinates );
01070 }
01071 if( metrics_request_flag & V_TRI_ASPECT_FROBENIUS ) // there is no V_TRI_ASPECT_RATIO !
01072 {
01073 metric_vals->aspect_ratio = v_tri_radius_ratio( 3, coordinates );
01074 }
01075 }