LCOV - code coverage report
Current view: top level - src/verdict - V_TriMetric.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 310 443 70.0 %
Date: 2020-12-16 07:07:30 Functions: 16 17 94.1 %
Branches: 296 790 37.5 %

           Branch data     Line data    Source code
       1                 :            : /*=========================================================================
       2                 :            : 
       3                 :            :   Module:    $RCSfile: V_TriMetric.cpp,v $
       4                 :            : 
       5                 :            :   Copyright (c) 2007 Sandia Corporation.
       6                 :            :   All rights reserved.
       7                 :            :   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
       8                 :            : 
       9                 :            :      This software is distributed WITHOUT ANY WARRANTY; without even
      10                 :            :      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
      11                 :            :      PURPOSE.  See the above copyright notice for more information.
      12                 :            : 
      13                 :            : =========================================================================*/
      14                 :            : 
      15                 :            : /*
      16                 :            :  *
      17                 :            :  * TriMetric.cpp contains quality calculations for Tris
      18                 :            :  *
      19                 :            :  * This file is part of VERDICT
      20                 :            :  *
      21                 :            :  */
      22                 :            : 
      23                 :            : #define VERDICT_EXPORTS
      24                 :            : 
      25                 :            : #include "moab/verdict.h"
      26                 :            : #include "verdict_defines.hpp"
      27                 :            : #include "V_GaussIntegration.hpp"
      28                 :            : #include "VerdictVector.hpp"
      29                 :            : #include <memory.h>
      30                 :            : #include <stddef.h>
      31                 :            : 
      32                 :            : // the average area of a tri
      33                 :            : static double verdict_tri_size      = 0;
      34                 :            : static ComputeNormal compute_normal = NULL;
      35                 :            : 
      36                 :            : /*!
      37                 :            :   get weights based on the average area of a set of
      38                 :            :   tris
      39                 :            : */
      40                 :         56 : static int v_tri_get_weight( double& m11, double& m21, double& m12, double& m22 )
      41                 :            : {
      42                 :            :     static const double rootOf3 = sqrt( 3.0 );
      43                 :         56 :     m11                         = 1;
      44                 :         56 :     m21                         = 0;
      45                 :         56 :     m12                         = 0.5;
      46                 :         56 :     m22                         = 0.5 * rootOf3;
      47                 :         56 :     double scale                = sqrt( 2.0 * verdict_tri_size / ( m11 * m22 - m21 * m12 ) );
      48                 :            : 
      49                 :         56 :     m11 *= scale;
      50                 :         56 :     m21 *= scale;
      51                 :         56 :     m12 *= scale;
      52                 :         56 :     m22 *= scale;
      53                 :            : 
      54                 :         56 :     return 1;
      55                 :            : }
      56                 :            : 
      57                 :            : /*! sets the average area of a tri */
      58                 :          1 : C_FUNC_DEF void v_set_tri_size( double size )
      59                 :            : {
      60                 :          1 :     verdict_tri_size = size;
      61                 :          1 : }
      62                 :            : 
      63                 :          0 : C_FUNC_DEF void v_set_tri_normal_func( ComputeNormal func )
      64                 :            : {
      65                 :          0 :     compute_normal = func;
      66                 :          0 : }
      67                 :            : 
      68                 :            : /*!
      69                 :            :    the edge ratio of a triangle
      70                 :            : 
      71                 :            :    NB (P. Pebay 01/14/07):
      72                 :            :      Hmax / Hmin where Hmax and Hmin are respectively the maximum and the
      73                 :            :      minimum edge lengths
      74                 :            : 
      75                 :            : */
      76                 :         36 : C_FUNC_DEF double v_tri_edge_ratio( int /*num_nodes*/, double coordinates[][3] )
      77                 :            : {
      78                 :            : 
      79                 :            :     // three vectors for each side
      80                 :         72 :     VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
      81         [ +  - ]:         36 :                      coordinates[1][2] - coordinates[0][2] );
      82                 :            : 
      83                 :         72 :     VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
      84         [ +  - ]:         36 :                      coordinates[2][2] - coordinates[1][2] );
      85                 :            : 
      86                 :         72 :     VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
      87         [ +  - ]:         36 :                      coordinates[0][2] - coordinates[2][2] );
      88                 :            : 
      89         [ +  - ]:         36 :     double a2 = a.length_squared();
      90         [ +  - ]:         36 :     double b2 = b.length_squared();
      91         [ +  - ]:         36 :     double c2 = c.length_squared();
      92                 :            : 
      93                 :            :     double m2, M2;
      94         [ +  + ]:         36 :     if( a2 < b2 )
      95                 :            :     {
      96         [ -  + ]:          8 :         if( b2 < c2 )
      97                 :            :         {
      98                 :          0 :             m2 = a2;
      99                 :          0 :             M2 = c2;
     100                 :            :         }
     101                 :            :         else  // b2 <= a2
     102                 :            :         {
     103         [ -  + ]:          8 :             if( a2 < c2 )
     104                 :            :             {
     105                 :          0 :                 m2 = a2;
     106                 :          0 :                 M2 = b2;
     107                 :            :             }
     108                 :            :             else  // c2 <= a2
     109                 :            :             {
     110                 :          8 :                 m2 = c2;
     111                 :          8 :                 M2 = b2;
     112                 :            :             }
     113                 :            :         }
     114                 :            :     }
     115                 :            :     else  // b2 <= a2
     116                 :            :     {
     117         [ +  + ]:         28 :         if( a2 < c2 )
     118                 :            :         {
     119                 :         18 :             m2 = b2;
     120                 :         18 :             M2 = c2;
     121                 :            :         }
     122                 :            :         else  // c2 <= a2
     123                 :            :         {
     124         [ -  + ]:         10 :             if( b2 < c2 )
     125                 :            :             {
     126                 :          0 :                 m2 = b2;
     127                 :          0 :                 M2 = a2;
     128                 :            :             }
     129                 :            :             else  // c2 <= b2
     130                 :            :             {
     131                 :         10 :                 m2 = c2;
     132                 :         10 :                 M2 = a2;
     133                 :            :             }
     134                 :            :         }
     135                 :            :     }
     136                 :            : 
     137         [ -  + ]:         36 :     if( m2 < VERDICT_DBL_MIN )
     138                 :          0 :         return (double)VERDICT_DBL_MAX;
     139                 :            :     else
     140                 :            :     {
     141                 :            :         double edge_ratio;
     142                 :         36 :         edge_ratio = sqrt( M2 / m2 );
     143                 :            : 
     144 [ +  - ][ +  - ]:         36 :         if( edge_ratio > 0 ) return (double)VERDICT_MIN( edge_ratio, VERDICT_DBL_MAX );
     145         [ #  # ]:         36 :         return (double)VERDICT_MAX( edge_ratio, -VERDICT_DBL_MAX );
     146                 :            :     }
     147                 :            : }
     148                 :            : 
     149                 :            : /*!
     150                 :            :    the aspect ratio of a triangle
     151                 :            : 
     152                 :            :    NB (P. Pebay 01/14/07):
     153                 :            :      Hmax / ( 2.0 * sqrt(3.0) * IR) where Hmax is the maximum edge length
     154                 :            :      and IR is the inradius
     155                 :            : 
     156                 :            :      note that previous incarnations of verdict used "v_tri_aspect_ratio" to denote
     157                 :            :      what is now called "v_tri_aspect_frobenius"
     158                 :            : 
     159                 :            : */
     160                 :         18 : C_FUNC_DEF double v_tri_aspect_ratio( int /*num_nodes*/, double coordinates[][3] )
     161                 :            : {
     162                 :            :     static const double normal_coeff = sqrt( 3. ) / 6.;
     163                 :            : 
     164                 :            :     // three vectors for each side
     165                 :         36 :     VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     166         [ +  - ]:         18 :                      coordinates[1][2] - coordinates[0][2] );
     167                 :            : 
     168                 :         36 :     VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
     169         [ +  - ]:         18 :                      coordinates[2][2] - coordinates[1][2] );
     170                 :            : 
     171                 :         36 :     VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
     172         [ +  - ]:         18 :                      coordinates[0][2] - coordinates[2][2] );
     173                 :            : 
     174         [ +  - ]:         18 :     double a1 = a.length();
     175         [ +  - ]:         18 :     double b1 = b.length();
     176         [ +  - ]:         18 :     double c1 = c.length();
     177                 :            : 
     178         [ +  + ]:         18 :     double hm = a1 > b1 ? a1 : b1;
     179         [ +  + ]:         18 :     hm        = hm > c1 ? hm : c1;
     180                 :            : 
     181         [ +  - ]:         18 :     VerdictVector ab   = a * b;
     182         [ +  - ]:         18 :     double denominator = ab.length();
     183                 :            : 
     184         [ -  + ]:         18 :     if( denominator < VERDICT_DBL_MIN )
     185                 :          0 :         return (double)VERDICT_DBL_MAX;
     186                 :            :     else
     187                 :            :     {
     188                 :            :         double aspect_ratio;
     189                 :         18 :         aspect_ratio = normal_coeff * hm * ( a1 + b1 + c1 ) / denominator;
     190                 :            : 
     191 [ +  - ][ +  - ]:         18 :         if( aspect_ratio > 0 ) return (double)VERDICT_MIN( aspect_ratio, VERDICT_DBL_MAX );
     192         [ #  # ]:         18 :         return (double)VERDICT_MAX( aspect_ratio, -VERDICT_DBL_MAX );
     193                 :            :     }
     194                 :            : }
     195                 :            : 
     196                 :            : /*!
     197                 :            :    the radius ratio of a triangle
     198                 :            : 
     199                 :            :    NB (P. Pebay 01/13/07):
     200                 :            :      CR / (3.0*IR) where CR is the circumradius and IR is the inradius
     201                 :            : 
     202                 :            :      this quality metric is also known to VERDICT, for tetrahedral elements only,
     203                 :            :      a the "aspect beta"
     204                 :            : 
     205                 :            : */
     206                 :         54 : C_FUNC_DEF double v_tri_radius_ratio( int /*num_nodes*/, double coordinates[][3] )
     207                 :            : {
     208                 :            : 
     209                 :            :     // three vectors for each side
     210                 :        108 :     VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     211         [ +  - ]:         54 :                      coordinates[1][2] - coordinates[0][2] );
     212                 :            : 
     213                 :        108 :     VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
     214         [ +  - ]:         54 :                      coordinates[2][2] - coordinates[1][2] );
     215                 :            : 
     216                 :        108 :     VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
     217         [ +  - ]:         54 :                      coordinates[0][2] - coordinates[2][2] );
     218                 :            : 
     219         [ +  - ]:         54 :     double a2 = a.length_squared();
     220         [ +  - ]:         54 :     double b2 = b.length_squared();
     221         [ +  - ]:         54 :     double c2 = c.length_squared();
     222                 :            : 
     223         [ +  - ]:         54 :     VerdictVector ab   = a * b;
     224         [ +  - ]:         54 :     double denominator = ab.length_squared();
     225                 :            : 
     226         [ -  + ]:         54 :     if( denominator < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX;
     227                 :            : 
     228                 :            :     double radius_ratio;
     229                 :         54 :     radius_ratio = .25 * a2 * b2 * c2 * ( a2 + b2 + c2 ) / denominator;
     230                 :            : 
     231 [ +  - ][ +  - ]:         54 :     if( radius_ratio > 0 ) return (double)VERDICT_MIN( radius_ratio, VERDICT_DBL_MAX );
     232         [ #  # ]:         54 :     return (double)VERDICT_MAX( radius_ratio, -VERDICT_DBL_MAX );
     233                 :            : }
     234                 :            : 
     235                 :            : /*!
     236                 :            :    the Frobenius aspect of a tri
     237                 :            : 
     238                 :            :    srms^2/(2 * sqrt(3.0) * area)
     239                 :            :    where srms^2 is sum of the lengths squared
     240                 :            : 
     241                 :            :    NB (P. Pebay 01/14/07):
     242                 :            :      this method was called "aspect ratio" in earlier incarnations of VERDICT
     243                 :            : 
     244                 :            : */
     245                 :            : 
     246                 :         18 : C_FUNC_DEF double v_tri_aspect_frobenius( int /*num_nodes*/, double coordinates[][3] )
     247                 :            : {
     248                 :            :     static const double two_times_root_of_3 = 2 * sqrt( 3.0 );
     249                 :            : 
     250                 :            :     // three vectors for each side
     251                 :         36 :     VerdictVector side1( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     252         [ +  - ]:         18 :                          coordinates[1][2] - coordinates[0][2] );
     253                 :            : 
     254                 :         36 :     VerdictVector side2( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
     255         [ +  - ]:         18 :                          coordinates[2][2] - coordinates[1][2] );
     256                 :            : 
     257                 :         36 :     VerdictVector side3( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
     258         [ +  - ]:         18 :                          coordinates[0][2] - coordinates[2][2] );
     259                 :            : 
     260                 :            :     // sum the lengths squared of each side
     261 [ +  - ][ +  - ]:         18 :     double srms = ( side1.length_squared() + side2.length_squared() + side3.length_squared() );
                 [ +  - ]
     262                 :            : 
     263                 :            :     // find two times the area of the triangle by cross product
     264 [ +  - ][ +  - ]:         18 :     double areaX2 = ( ( side1 * ( -side3 ) ).length() );
                 [ +  - ]
     265                 :            : 
     266         [ -  + ]:         18 :     if( areaX2 == 0.0 ) return (double)VERDICT_DBL_MAX;
     267                 :            : 
     268                 :         18 :     double aspect = (double)( srms / ( two_times_root_of_3 * ( areaX2 ) ) );
     269 [ +  - ][ +  - ]:         18 :     if( aspect > 0 ) return (double)VERDICT_MIN( aspect, VERDICT_DBL_MAX );
     270         [ #  # ]:         18 :     return (double)VERDICT_MAX( aspect, -VERDICT_DBL_MAX );
     271                 :            : }
     272                 :            : 
     273                 :            : /*!
     274                 :            :   The area of a tri
     275                 :            : 
     276                 :            :   0.5 * jacobian at a node
     277                 :            : */
     278                 :         19 : C_FUNC_DEF double v_tri_area( int /*num_nodes*/, double coordinates[][3] )
     279                 :            : {
     280                 :            :     // two vectors for two sides
     281                 :         38 :     VerdictVector side1( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     282         [ +  - ]:         19 :                          coordinates[1][2] - coordinates[0][2] );
     283                 :            : 
     284                 :         38 :     VerdictVector side3( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
     285         [ +  - ]:         19 :                          coordinates[2][2] - coordinates[0][2] );
     286                 :            : 
     287                 :            :     // the cross product of the two vectors representing two sides of the
     288                 :            :     // triangle
     289         [ +  - ]:         19 :     VerdictVector tmp = side1 * side3;
     290                 :            : 
     291                 :            :     // return the magnitude of the vector divided by two
     292         [ +  - ]:         19 :     double area = 0.5 * tmp.length();
     293 [ +  - ][ +  - ]:         19 :     if( area > 0 ) return (double)VERDICT_MIN( area, VERDICT_DBL_MAX );
     294         [ #  # ]:         19 :     return (double)VERDICT_MAX( area, -VERDICT_DBL_MAX );
     295                 :            : }
     296                 :            : 
     297                 :            : /*!
     298                 :            :   The minimum angle of a tri
     299                 :            : 
     300                 :            :   The minimum angle of a tri is the minimum angle between
     301                 :            :   two adjacents sides out of all three corners of the triangle.
     302                 :            : */
     303                 :         19 : C_FUNC_DEF double v_tri_minimum_angle( int /*num_nodes*/, double coordinates[][3] )
     304                 :            : {
     305                 :            : 
     306                 :            :     // vectors for all the sides
     307 [ +  - ][ +  + ]:         95 :     VerdictVector sides[4];
     308                 :         38 :     sides[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     309         [ +  - ]:         19 :                   coordinates[1][2] - coordinates[0][2] );
     310                 :         38 :     sides[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
     311         [ +  - ]:         19 :                   coordinates[2][2] - coordinates[1][2] );
     312                 :         38 :     sides[2].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
     313         [ +  - ]:         19 :                   coordinates[2][2] - coordinates[0][2] );
     314                 :            : 
     315                 :            :     // in case we need to find the interior angle
     316                 :            :     // between sides 0 and 1
     317 [ +  - ][ +  - ]:         19 :     sides[3] = -sides[1];
     318                 :            : 
     319                 :            :     // calculate the lengths squared of the sides
     320                 :            :     double sides_lengths[3];
     321         [ +  - ]:         19 :     sides_lengths[0] = sides[0].length_squared();
     322         [ +  - ]:         19 :     sides_lengths[1] = sides[1].length_squared();
     323         [ +  - ]:         19 :     sides_lengths[2] = sides[2].length_squared();
     324                 :            : 
     325 [ +  - ][ +  - ]:         19 :     if( sides_lengths[0] == 0.0 || sides_lengths[1] == 0.0 || sides_lengths[2] == 0.0 ) return 0.0;
                 [ -  + ]
     326                 :            : 
     327                 :            :     // using the law of sines, we know that the minimum
     328                 :            :     // angle is opposite of the shortest side
     329                 :            : 
     330                 :            :     // find the shortest side
     331                 :         19 :     int short_side = 0;
     332         [ +  + ]:         19 :     if( sides_lengths[1] < sides_lengths[0] ) short_side = 1;
     333         [ -  + ]:         19 :     if( sides_lengths[2] < sides_lengths[short_side] ) short_side = 2;
     334                 :            : 
     335                 :            :     // from the shortest side, calculate the angle of the
     336                 :            :     // opposite angle
     337                 :            :     double min_angle;
     338 [ +  + ][ +  - ]:         19 :     if( short_side == 0 ) { min_angle = sides[2].interior_angle( sides[1] ); }
     339         [ +  - ]:          6 :     else if( short_side == 1 )
     340                 :            :     {
     341         [ +  - ]:          6 :         min_angle = sides[0].interior_angle( sides[2] );
     342                 :            :     }
     343                 :            :     else
     344                 :            :     {
     345         [ #  # ]:          0 :         min_angle = sides[0].interior_angle( sides[3] );
     346                 :            :     }
     347                 :            : 
     348 [ +  - ][ +  - ]:         19 :     if( min_angle > 0 ) return (double)VERDICT_MIN( min_angle, VERDICT_DBL_MAX );
     349         [ #  # ]:         19 :     return (double)VERDICT_MAX( min_angle, -VERDICT_DBL_MAX );
     350                 :            : }
     351                 :            : 
     352                 :            : /*!
     353                 :            :   The maximum angle of a tri
     354                 :            : 
     355                 :            :   The maximum angle of a tri is the maximum angle between
     356                 :            :   two adjacents sides out of all three corners of the triangle.
     357                 :            : */
     358                 :         19 : C_FUNC_DEF double v_tri_maximum_angle( int /*num_nodes*/, double coordinates[][3] )
     359                 :            : {
     360                 :            : 
     361                 :            :     // vectors for all the sides
     362 [ +  - ][ +  + ]:         95 :     VerdictVector sides[4];
     363                 :         38 :     sides[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     364         [ +  - ]:         19 :                   coordinates[1][2] - coordinates[0][2] );
     365                 :         38 :     sides[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
     366         [ +  - ]:         19 :                   coordinates[2][2] - coordinates[1][2] );
     367                 :         38 :     sides[2].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
     368         [ +  - ]:         19 :                   coordinates[2][2] - coordinates[0][2] );
     369                 :            : 
     370                 :            :     // in case we need to find the interior angle
     371                 :            :     // between sides 0 and 1
     372 [ +  - ][ +  - ]:         19 :     sides[3] = -sides[1];
     373                 :            : 
     374                 :            :     // calculate the lengths squared of the sides
     375                 :            :     double sides_lengths[3];
     376         [ +  - ]:         19 :     sides_lengths[0] = sides[0].length_squared();
     377         [ +  - ]:         19 :     sides_lengths[1] = sides[1].length_squared();
     378         [ +  - ]:         19 :     sides_lengths[2] = sides[2].length_squared();
     379                 :            : 
     380 [ +  - ][ +  - ]:         19 :     if( sides_lengths[0] == 0.0 || sides_lengths[1] == 0.0 || sides_lengths[2] == 0.0 ) { return 0.0; }
                 [ -  + ]
     381                 :            : 
     382                 :            :     // using the law of sines, we know that the maximum
     383                 :            :     // angle is opposite of the longest side
     384                 :            : 
     385                 :            :     // find the longest side
     386                 :         19 :     int short_side = 0;
     387         [ +  + ]:         19 :     if( sides_lengths[1] > sides_lengths[0] ) short_side = 1;
     388         [ +  + ]:         19 :     if( sides_lengths[2] > sides_lengths[short_side] ) short_side = 2;
     389                 :            : 
     390                 :            :     // from the longest side, calculate the angle of the
     391                 :            :     // opposite angle
     392                 :            :     double max_angle;
     393 [ +  + ][ +  - ]:         19 :     if( short_side == 0 ) { max_angle = sides[2].interior_angle( sides[1] ); }
     394         [ +  + ]:         13 :     else if( short_side == 1 )
     395                 :            :     {
     396         [ +  - ]:          4 :         max_angle = sides[0].interior_angle( sides[2] );
     397                 :            :     }
     398                 :            :     else
     399                 :            :     {
     400         [ +  - ]:          9 :         max_angle = sides[0].interior_angle( sides[3] );
     401                 :            :     }
     402                 :            : 
     403 [ +  - ][ +  - ]:         19 :     if( max_angle > 0 ) return (double)VERDICT_MIN( max_angle, VERDICT_DBL_MAX );
     404         [ #  # ]:         19 :     return (double)VERDICT_MAX( max_angle, -VERDICT_DBL_MAX );
     405                 :            : }
     406                 :            : 
     407                 :            : /*!
     408                 :            :   The condition of a tri
     409                 :            : 
     410                 :            :   Condition number of the jacobian matrix at any corner
     411                 :            : */
     412                 :         57 : C_FUNC_DEF double v_tri_condition( int /*num_nodes*/, double coordinates[][3] )
     413                 :            : {
     414                 :            :     static const double rt3 = sqrt( 3.0 );
     415                 :            : 
     416                 :        114 :     VerdictVector v1( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     417         [ +  - ]:         57 :                       coordinates[1][2] - coordinates[0][2] );
     418                 :            : 
     419                 :        114 :     VerdictVector v2( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
     420         [ +  - ]:         57 :                       coordinates[2][2] - coordinates[0][2] );
     421                 :            : 
     422         [ +  - ]:         57 :     VerdictVector tri_normal = v1 * v2;
     423         [ +  - ]:         57 :     double areax2            = tri_normal.length();
     424                 :            : 
     425         [ -  + ]:         57 :     if( areax2 == 0.0 ) return (double)VERDICT_DBL_MAX;
     426                 :            : 
     427 [ +  - ][ +  - ]:         57 :     double condition = (double)( ( ( v1 % v1 ) + ( v2 % v2 ) - ( v1 % v2 ) ) / ( areax2 * rt3 ) );
                 [ +  - ]
     428                 :            : 
     429                 :            :     // check for inverted if we have access to the normal
     430         [ -  + ]:         57 :     if( compute_normal )
     431                 :            :     {
     432                 :            :         // center of tri
     433                 :            :         double point[3], surf_normal[3];
     434                 :          0 :         point[0] = ( coordinates[0][0] + coordinates[1][0] + coordinates[2][0] ) / 3;
     435                 :          0 :         point[1] = ( coordinates[0][1] + coordinates[1][1] + coordinates[2][1] ) / 3;
     436                 :          0 :         point[2] = ( coordinates[0][2] + coordinates[1][2] + coordinates[2][2] ) / 3;
     437                 :            : 
     438                 :            :         // dot product
     439         [ #  # ]:          0 :         compute_normal( point, surf_normal );
     440 [ #  # ][ #  # ]:          0 :         if( ( tri_normal.x() * surf_normal[0] + tri_normal.y() * surf_normal[1] + tri_normal.z() * surf_normal[2] ) <
         [ #  # ][ #  # ]
     441                 :            :             0 )
     442                 :          0 :             return (double)VERDICT_DBL_MAX;
     443                 :            :     }
     444         [ +  - ]:         57 :     return (double)VERDICT_MIN( condition, VERDICT_DBL_MAX );
     445                 :            : }
     446                 :            : 
     447                 :            : /*!
     448                 :            :   The scaled jacobian of a tri
     449                 :            : 
     450                 :            :   minimum of the jacobian divided by the lengths of 2 edge vectors
     451                 :            : */
     452                 :         19 : C_FUNC_DEF double v_tri_scaled_jacobian( int /*num_nodes*/, double coordinates[][3] )
     453                 :            : {
     454                 :            :     static const double detw = 2. / sqrt( 3.0 );
     455 [ +  - ][ +  - ]:         19 :     VerdictVector first, second;
     456                 :            :     double jacobian;
     457                 :            : 
     458 [ +  - ][ +  + ]:         76 :     VerdictVector edge[3];
     459                 :         38 :     edge[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     460         [ +  - ]:         19 :                  coordinates[1][2] - coordinates[0][2] );
     461                 :            : 
     462                 :         38 :     edge[1].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
     463         [ +  - ]:         19 :                  coordinates[2][2] - coordinates[0][2] );
     464                 :            : 
     465                 :         38 :     edge[2].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
     466         [ +  - ]:         19 :                  coordinates[2][2] - coordinates[1][2] );
     467 [ +  - ][ +  - ]:         19 :     first  = edge[1] - edge[0];
     468 [ +  - ][ +  - ]:         19 :     second = edge[2] - edge[0];
     469                 :            : 
     470         [ +  - ]:         19 :     VerdictVector cross = first * second;
     471         [ +  - ]:         19 :     jacobian            = cross.length();
     472                 :            : 
     473                 :            :     double max_edge_length_product;
     474                 :            :     max_edge_length_product =
     475 [ +  - ][ +  - ]:         57 :         VERDICT_MAX( edge[0].length() * edge[1].length(),
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ #  # ]
         [ #  # ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     476 [ -  + ][ +  + ]:         57 :                      VERDICT_MAX( edge[1].length() * edge[2].length(), edge[0].length() * edge[2].length() ) );
     477                 :            : 
     478         [ -  + ]:         19 :     if( max_edge_length_product < VERDICT_DBL_MIN ) return (double)0.0;
     479                 :            : 
     480                 :         19 :     jacobian *= detw;
     481                 :         19 :     jacobian /= max_edge_length_product;
     482                 :            : 
     483         [ -  + ]:         19 :     if( compute_normal )
     484                 :            :     {
     485                 :            :         // center of tri
     486                 :            :         double point[3], surf_normal[3];
     487                 :          0 :         point[0] = ( coordinates[0][0] + coordinates[1][0] + coordinates[2][0] ) / 3;
     488                 :          0 :         point[1] = ( coordinates[0][1] + coordinates[1][1] + coordinates[2][1] ) / 3;
     489                 :          0 :         point[2] = ( coordinates[0][2] + coordinates[1][2] + coordinates[2][2] ) / 3;
     490                 :            : 
     491                 :            :         // dot product
     492         [ #  # ]:          0 :         compute_normal( point, surf_normal );
     493 [ #  # ][ #  # ]:          0 :         if( ( cross.x() * surf_normal[0] + cross.y() * surf_normal[1] + cross.z() * surf_normal[2] ) < 0 )
         [ #  # ][ #  # ]
     494                 :          0 :             jacobian *= -1;
     495                 :            :     }
     496                 :            : 
     497 [ +  - ][ +  - ]:         19 :     if( jacobian > 0 ) return (double)VERDICT_MIN( jacobian, VERDICT_DBL_MAX );
     498         [ #  # ]:         19 :     return (double)VERDICT_MAX( jacobian, -VERDICT_DBL_MAX );
     499                 :            : }
     500                 :            : 
     501                 :            : /*!
     502                 :            :   The shape of a tri
     503                 :            : 
     504                 :            :   2 / condition number of weighted jacobian matrix
     505                 :            : */
     506                 :         38 : C_FUNC_DEF double v_tri_shape( int num_nodes, double coordinates[][3] )
     507                 :            : {
     508                 :         38 :     double condition = v_tri_condition( num_nodes, coordinates );
     509                 :            : 
     510                 :            :     double shape;
     511         [ -  + ]:         38 :     if( condition <= VERDICT_DBL_MIN )
     512                 :          0 :         shape = VERDICT_DBL_MAX;
     513                 :            :     else
     514                 :         38 :         shape = ( 1 / condition );
     515                 :            : 
     516 [ +  - ][ +  - ]:         38 :     if( shape > 0 ) return (double)VERDICT_MIN( shape, VERDICT_DBL_MAX );
     517         [ #  # ]:          0 :     return (double)VERDICT_MAX( shape, -VERDICT_DBL_MAX );
     518                 :            : }
     519                 :            : 
     520                 :            : /*!
     521                 :            :   The relative size of a tri
     522                 :            : 
     523                 :            :   Min(J,1/J) where J is the determinant of the weighted jacobian matrix.
     524                 :            : */
     525                 :         38 : C_FUNC_DEF double v_tri_relative_size_squared( int /*num_nodes*/, double coordinates[][3] )
     526                 :            : {
     527                 :            :     double w11, w21, w12, w22;
     528                 :            : 
     529 [ +  - ][ +  - ]:         38 :     VerdictVector xxi, xet, tri_normal;
                 [ +  - ]
     530                 :            : 
     531                 :         38 :     v_tri_get_weight( w11, w21, w12, w22 );
     532                 :            : 
     533         [ +  - ]:         38 :     double detw = determinant( w11, w21, w12, w22 );
     534                 :            : 
     535         [ -  + ]:         38 :     if( detw == 0.0 ) return 0.0;
     536                 :            : 
     537                 :         76 :     xxi.set( coordinates[0][0] - coordinates[1][0], coordinates[0][1] - coordinates[1][1],
     538         [ +  - ]:         38 :              coordinates[0][2] - coordinates[1][2] );
     539                 :            : 
     540                 :         76 :     xet.set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1],
     541         [ +  - ]:         38 :              coordinates[0][2] - coordinates[2][2] );
     542                 :            : 
     543 [ +  - ][ +  - ]:         38 :     tri_normal = xxi * xet;
     544                 :            : 
     545         [ +  - ]:         38 :     double deta = tri_normal.length();
     546 [ +  - ][ -  + ]:         38 :     if( deta == 0.0 || detw == 0.0 ) return 0.0;
     547                 :            : 
     548                 :         38 :     double size = pow( deta / detw, 2 );
     549                 :            : 
     550         [ +  + ]:         38 :     double rel_size = VERDICT_MIN( size, 1.0 / size );
     551                 :            : 
     552 [ +  - ][ +  - ]:         38 :     if( rel_size > 0 ) return (double)VERDICT_MIN( rel_size, VERDICT_DBL_MAX );
     553         [ #  # ]:         38 :     return (double)VERDICT_MAX( rel_size, -VERDICT_DBL_MAX );
     554                 :            : }
     555                 :            : 
     556                 :            : /*!
     557                 :            :   The shape and size of a tri
     558                 :            : 
     559                 :            :   Product of the Shape and Relative Size
     560                 :            : */
     561                 :         19 : C_FUNC_DEF double v_tri_shape_and_size( int num_nodes, double coordinates[][3] )
     562                 :            : {
     563                 :            :     double size, shape;
     564                 :            : 
     565                 :         19 :     size  = v_tri_relative_size_squared( num_nodes, coordinates );
     566                 :         19 :     shape = v_tri_shape( num_nodes, coordinates );
     567                 :            : 
     568                 :         19 :     double shape_and_size = size * shape;
     569                 :            : 
     570 [ +  - ][ +  - ]:         19 :     if( shape_and_size > 0 ) return (double)VERDICT_MIN( shape_and_size, VERDICT_DBL_MAX );
     571         [ #  # ]:          0 :     return (double)VERDICT_MAX( shape_and_size, -VERDICT_DBL_MAX );
     572                 :            : }
     573                 :            : 
     574                 :            : /*!
     575                 :            :   The distortion of a tri
     576                 :            : 
     577                 :            : TODO:  make a short definition of the distortion and comment below
     578                 :            : */
     579                 :         37 : C_FUNC_DEF double v_tri_distortion( int num_nodes, double coordinates[][3] )
     580                 :            : {
     581                 :            : 
     582                 :            :     double distortion;
     583                 :         37 :     int total_number_of_gauss_points = 0;
     584 [ +  - ][ +  - ]:         37 :     VerdictVector aa, bb, cc, normal_at_point, xin;
         [ +  - ][ +  - ]
                 [ +  - ]
     585                 :         37 :     double element_area = 0.;
     586                 :            : 
     587                 :         74 :     aa.set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     588         [ +  - ]:         37 :             coordinates[1][2] - coordinates[0][2] );
     589                 :            : 
     590                 :         74 :     bb.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
     591         [ +  - ]:         37 :             coordinates[2][2] - coordinates[0][2] );
     592                 :            : 
     593         [ +  - ]:         37 :     VerdictVector tri_normal = aa * bb;
     594                 :            : 
     595                 :         37 :     int number_of_gauss_points = 0;
     596         [ +  - ]:         37 :     if( num_nodes == 3 )
     597                 :            :     {
     598                 :         37 :         distortion = 1.0;
     599                 :         37 :         return (double)distortion;
     600                 :            :     }
     601                 :            : 
     602         [ #  # ]:          0 :     else if( num_nodes == 6 )
     603                 :            :     {
     604                 :          0 :         total_number_of_gauss_points = 6;
     605                 :          0 :         number_of_gauss_points       = 6;
     606                 :            :     }
     607                 :            : 
     608                 :          0 :     distortion = VERDICT_DBL_MAX;
     609                 :            :     double shape_function[maxTotalNumberGaussPoints][maxNumberNodes];
     610                 :            :     double dndy1[maxTotalNumberGaussPoints][maxNumberNodes];
     611                 :            :     double dndy2[maxTotalNumberGaussPoints][maxNumberNodes];
     612                 :            :     double weight[maxTotalNumberGaussPoints];
     613                 :            : 
     614                 :            :     // create an object of GaussIntegration
     615                 :          0 :     int number_dims = 2;
     616                 :          0 :     int is_tri      = 1;
     617         [ #  # ]:          0 :     GaussIntegration::initialize( number_of_gauss_points, num_nodes, number_dims, is_tri );
     618         [ #  # ]:          0 :     GaussIntegration::calculate_shape_function_2d_tri();
     619         [ #  # ]:          0 :     GaussIntegration::get_shape_func( shape_function[0], dndy1[0], dndy2[0], weight );
     620                 :            : 
     621                 :            :     // calculate element area
     622                 :            :     int ife, ja;
     623         [ #  # ]:          0 :     for( ife = 0; ife < total_number_of_gauss_points; ife++ )
     624                 :            :     {
     625         [ #  # ]:          0 :         aa.set( 0.0, 0.0, 0.0 );
     626         [ #  # ]:          0 :         bb.set( 0.0, 0.0, 0.0 );
     627                 :            : 
     628         [ #  # ]:          0 :         for( ja = 0; ja < num_nodes; ja++ )
     629                 :            :         {
     630         [ #  # ]:          0 :             xin.set( coordinates[ja][0], coordinates[ja][1], coordinates[ja][2] );
     631 [ #  # ][ #  # ]:          0 :             aa += dndy1[ife][ja] * xin;
     632 [ #  # ][ #  # ]:          0 :             bb += dndy2[ife][ja] * xin;
     633                 :            :         }
     634 [ #  # ][ #  # ]:          0 :         normal_at_point = aa * bb;
     635         [ #  # ]:          0 :         double jacobian = normal_at_point.length();
     636                 :          0 :         element_area += weight[ife] * jacobian;
     637                 :            :     }
     638                 :            : 
     639                 :          0 :     element_area *= 0.8660254;
     640                 :            :     double dndy1_at_node[maxNumberNodes][maxNumberNodes];
     641                 :            :     double dndy2_at_node[maxNumberNodes][maxNumberNodes];
     642                 :            : 
     643         [ #  # ]:          0 :     GaussIntegration::calculate_derivative_at_nodes_2d_tri( dndy1_at_node, dndy2_at_node );
     644                 :            : 
     645 [ #  # ][ #  # ]:          0 :     VerdictVector normal_at_nodes[7];
     646                 :            : 
     647                 :            :     // evaluate normal at nodes and distortion values at nodes
     648                 :          0 :     int jai = 0;
     649         [ #  # ]:          0 :     for( ja = 0; ja < num_nodes; ja++ )
     650                 :            :     {
     651         [ #  # ]:          0 :         aa.set( 0.0, 0.0, 0.0 );
     652         [ #  # ]:          0 :         bb.set( 0.0, 0.0, 0.0 );
     653         [ #  # ]:          0 :         for( jai = 0; jai < num_nodes; jai++ )
     654                 :            :         {
     655         [ #  # ]:          0 :             xin.set( coordinates[jai][0], coordinates[jai][1], coordinates[jai][2] );
     656 [ #  # ][ #  # ]:          0 :             aa += dndy1_at_node[ja][jai] * xin;
     657 [ #  # ][ #  # ]:          0 :             bb += dndy2_at_node[ja][jai] * xin;
     658                 :            :         }
     659 [ #  # ][ #  # ]:          0 :         normal_at_nodes[ja] = aa * bb;
     660         [ #  # ]:          0 :         normal_at_nodes[ja].normalize();
     661                 :            :     }
     662                 :            : 
     663                 :            :     // determine if element is flat
     664                 :          0 :     bool flat_element = true;
     665                 :            :     double dot_product;
     666                 :            : 
     667         [ #  # ]:          0 :     for( ja = 0; ja < num_nodes; ja++ )
     668                 :            :     {
     669         [ #  # ]:          0 :         dot_product = normal_at_nodes[0] % normal_at_nodes[ja];
     670         [ #  # ]:          0 :         if( fabs( dot_product ) < 0.99 )
     671                 :            :         {
     672                 :          0 :             flat_element = false;
     673                 :          0 :             break;
     674                 :            :         }
     675                 :            :     }
     676                 :            : 
     677                 :            :     // take into consideration of the thickness of the element
     678                 :            :     double thickness, thickness_gauss;
     679                 :            :     double distrt;
     680                 :            :     // get_tri_thickness(tri, element_area, thickness );
     681                 :          0 :     thickness = 0.001 * sqrt( element_area );
     682                 :            : 
     683                 :            :     // set thickness gauss point location
     684                 :          0 :     double zl = 0.5773502691896;
     685         [ #  # ]:          0 :     if( flat_element ) zl = 0.0;
     686                 :            : 
     687         [ #  # ]:          0 :     int no_gauss_pts_z = ( flat_element ) ? 1 : 2;
     688                 :            :     double thickness_z;
     689                 :            : 
     690                 :            :     // loop on integration points
     691                 :            :     int igz;
     692         [ #  # ]:          0 :     for( ife = 0; ife < total_number_of_gauss_points; ife++ )
     693                 :            :     {
     694                 :            :         // loop on the thickness direction gauss points
     695         [ #  # ]:          0 :         for( igz = 0; igz < no_gauss_pts_z; igz++ )
     696                 :            :         {
     697                 :          0 :             zl          = -zl;
     698                 :          0 :             thickness_z = zl * thickness / 2.0;
     699                 :            : 
     700         [ #  # ]:          0 :             aa.set( 0.0, 0.0, 0.0 );
     701         [ #  # ]:          0 :             bb.set( 0.0, 0.0, 0.0 );
     702         [ #  # ]:          0 :             cc.set( 0.0, 0.0, 0.0 );
     703                 :            : 
     704         [ #  # ]:          0 :             for( ja = 0; ja < num_nodes; ja++ )
     705                 :            :             {
     706         [ #  # ]:          0 :                 xin.set( coordinates[jai][0], coordinates[jai][1], coordinates[jai][2] );
     707 [ #  # ][ #  # ]:          0 :                 xin += thickness_z * normal_at_nodes[ja];
     708 [ #  # ][ #  # ]:          0 :                 aa += dndy1[ife][ja] * xin;
     709 [ #  # ][ #  # ]:          0 :                 bb += dndy2[ife][ja] * xin;
     710                 :          0 :                 thickness_gauss = shape_function[ife][ja] * thickness / 2.0;
     711 [ #  # ][ #  # ]:          0 :                 cc += thickness_gauss * normal_at_nodes[ja];
     712                 :            :             }
     713                 :            : 
     714 [ #  # ][ #  # ]:          0 :             normal_at_point = aa * bb;
     715         [ #  # ]:          0 :             distrt          = cc % normal_at_point;
     716         [ #  # ]:          0 :             if( distrt < distortion ) distortion = distrt;
     717                 :            :         }
     718                 :            :     }
     719                 :            : 
     720                 :            :     // loop through nodal points
     721         [ #  # ]:          0 :     for( ja = 0; ja < num_nodes; ja++ )
     722                 :            :     {
     723         [ #  # ]:          0 :         for( igz = 0; igz < no_gauss_pts_z; igz++ )
     724                 :            :         {
     725                 :          0 :             zl          = -zl;
     726                 :          0 :             thickness_z = zl * thickness / 2.0;
     727                 :            : 
     728         [ #  # ]:          0 :             aa.set( 0.0, 0.0, 0.0 );
     729         [ #  # ]:          0 :             bb.set( 0.0, 0.0, 0.0 );
     730         [ #  # ]:          0 :             cc.set( 0.0, 0.0, 0.0 );
     731                 :            : 
     732         [ #  # ]:          0 :             for( jai = 0; jai < num_nodes; jai++ )
     733                 :            :             {
     734         [ #  # ]:          0 :                 xin.set( coordinates[jai][0], coordinates[jai][1], coordinates[jai][2] );
     735 [ #  # ][ #  # ]:          0 :                 xin += thickness_z * normal_at_nodes[ja];
     736 [ #  # ][ #  # ]:          0 :                 aa += dndy1_at_node[ja][jai] * xin;
     737 [ #  # ][ #  # ]:          0 :                 bb += dndy2_at_node[ja][jai] * xin;
     738         [ #  # ]:          0 :                 if( jai == ja )
     739                 :          0 :                     thickness_gauss = thickness / 2.0;
     740                 :            :                 else
     741                 :          0 :                     thickness_gauss = 0.;
     742 [ #  # ][ #  # ]:          0 :                 cc += thickness_gauss * normal_at_nodes[jai];
     743                 :            :             }
     744                 :            :         }
     745                 :            : 
     746 [ #  # ][ #  # ]:          0 :         normal_at_point      = aa * bb;
     747 [ #  # ][ #  # ]:          0 :         double sign_jacobian = ( tri_normal % normal_at_point ) > 0 ? 1. : -1.;
     748         [ #  # ]:          0 :         distrt               = sign_jacobian * ( cc % normal_at_point );
     749                 :            : 
     750         [ #  # ]:          0 :         if( distrt < distortion ) distortion = distrt;
     751                 :            :     }
     752         [ #  # ]:          0 :     if( element_area * thickness != 0 )
     753                 :          0 :         distortion *= 1. / ( element_area * thickness );
     754                 :            :     else
     755                 :          0 :         distortion *= 1.;
     756                 :            : 
     757 [ #  # ][ #  # ]:          0 :     if( distortion > 0 ) return (double)VERDICT_MIN( distortion, VERDICT_DBL_MAX );
     758         [ #  # ]:         37 :     return (double)VERDICT_MAX( distortion, -VERDICT_DBL_MAX );
     759                 :            : }
     760                 :            : 
     761                 :            : /*!
     762                 :            :   tri_quality for calculating multiple tri metrics at once
     763                 :            : 
     764                 :            :   using this method is generally faster than using the individual
     765                 :            :   method multiple times.
     766                 :            : 
     767                 :            : */
     768                 :         18 : C_FUNC_DEF void v_tri_quality( int num_nodes, double coordinates[][3], unsigned int metrics_request_flag,
     769                 :            :                                TriMetricVals* metric_vals )
     770                 :            : {
     771                 :            : 
     772                 :         18 :     memset( metric_vals, 0, sizeof( TriMetricVals ) );
     773                 :            : 
     774                 :            :     // for starts, lets set up some basic and common information
     775                 :            : 
     776                 :            :     /*  node numbers and side numbers used below
     777                 :            : 
     778                 :            :                2
     779                 :            :                ++
     780                 :            :               /  \
     781                 :            :            2 /    \ 1
     782                 :            :             /      \
     783                 :            :            /        \
     784                 :            :          0 ---------+ 1
     785                 :            :                0
     786                 :            :     */
     787                 :            : 
     788                 :            :     // vectors for each side
     789 [ +  - ][ +  + ]:         72 :     VerdictVector sides[3];
     790                 :         36 :     sides[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1],
     791         [ +  - ]:         18 :                   coordinates[1][2] - coordinates[0][2] );
     792                 :         36 :     sides[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1],
     793         [ +  - ]:         18 :                   coordinates[2][2] - coordinates[1][2] );
     794                 :         36 :     sides[2].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1],
     795         [ +  - ]:         18 :                   coordinates[2][2] - coordinates[0][2] );
     796         [ +  - ]:         18 :     VerdictVector tri_normal = sides[0] * sides[2];
     797                 :            :     // if we have access to normal information, check to see if the
     798                 :            :     // element is inverted.  If we don't have the normal information
     799                 :            :     // that we need for this, assume the element is not inverted.
     800                 :            :     // This flag will be used for condition number, jacobian, shape,
     801                 :            :     // and size and shape.
     802                 :         18 :     bool is_inverted = false;
     803         [ -  + ]:         18 :     if( compute_normal )
     804                 :            :     {
     805                 :            :         // center of tri
     806                 :            :         double point[3], surf_normal[3];
     807                 :          0 :         point[0] = ( coordinates[0][0] + coordinates[1][0] + coordinates[2][0] ) / 3;
     808                 :          0 :         point[1] = ( coordinates[0][1] + coordinates[1][1] + coordinates[2][1] ) / 3;
     809                 :          0 :         point[2] = ( coordinates[0][2] + coordinates[1][2] + coordinates[2][2] ) / 3;
     810                 :            :         // dot product
     811         [ #  # ]:          0 :         compute_normal( point, surf_normal );
     812 [ #  # ][ #  # ]:          0 :         if( ( tri_normal.x() * surf_normal[0] + tri_normal.y() * surf_normal[1] + tri_normal.z() * surf_normal[2] ) <
         [ #  # ][ #  # ]
     813                 :            :             0 )
     814                 :          0 :             is_inverted = true;
     815                 :            :     }
     816                 :            : 
     817                 :            :     // lengths squared of each side
     818                 :            :     double sides_lengths_squared[3];
     819         [ +  - ]:         18 :     sides_lengths_squared[0] = sides[0].length_squared();
     820         [ +  - ]:         18 :     sides_lengths_squared[1] = sides[1].length_squared();
     821         [ +  - ]:         18 :     sides_lengths_squared[2] = sides[2].length_squared();
     822                 :            : 
     823                 :            :     // if we are doing angle calcuations
     824         [ +  - ]:         18 :     if( metrics_request_flag & ( V_TRI_MINIMUM_ANGLE | V_TRI_MAXIMUM_ANGLE ) )
     825                 :            :     {
     826                 :            :         // which is short and long side
     827                 :         18 :         int short_side = 0, long_side = 0;
     828                 :            : 
     829         [ +  + ]:         18 :         if( sides_lengths_squared[1] < sides_lengths_squared[0] ) short_side = 1;
     830         [ -  + ]:         18 :         if( sides_lengths_squared[2] < sides_lengths_squared[short_side] ) short_side = 2;
     831                 :            : 
     832         [ +  + ]:         18 :         if( sides_lengths_squared[1] > sides_lengths_squared[0] ) long_side = 1;
     833         [ +  + ]:         18 :         if( sides_lengths_squared[2] > sides_lengths_squared[long_side] ) long_side = 2;
     834                 :            : 
     835                 :            :         // calculate the minimum angle of the tri
     836         [ +  - ]:         18 :         if( metrics_request_flag & V_TRI_MINIMUM_ANGLE )
     837                 :            :         {
     838 [ +  - ][ +  - ]:         18 :             if( sides_lengths_squared[0] == 0.0 || sides_lengths_squared[1] == 0.0 || sides_lengths_squared[2] == 0.0 )
                 [ -  + ]
     839                 :          0 :             { metric_vals->minimum_angle = 0.0; }
     840         [ +  + ]:         18 :             else if( short_side == 0 )
     841         [ +  - ]:         13 :                 metric_vals->minimum_angle = (double)sides[2].interior_angle( sides[1] );
     842         [ +  - ]:          5 :             else if( short_side == 1 )
     843         [ +  - ]:          5 :                 metric_vals->minimum_angle = (double)sides[0].interior_angle( sides[2] );
     844                 :            :             else
     845 [ #  # ][ #  # ]:         18 :                 metric_vals->minimum_angle = (double)sides[0].interior_angle( -sides[1] );
     846                 :            :         }
     847                 :            : 
     848                 :            :         // calculate the maximum angle of the tri
     849         [ +  - ]:         18 :         if( metrics_request_flag & V_TRI_MAXIMUM_ANGLE )
     850                 :            :         {
     851 [ +  - ][ +  - ]:         18 :             if( sides_lengths_squared[0] == 0.0 || sides_lengths_squared[1] == 0.0 || sides_lengths_squared[2] == 0.0 )
                 [ -  + ]
     852                 :          0 :             { metric_vals->maximum_angle = 0.0; }
     853         [ +  + ]:         18 :             else if( long_side == 0 )
     854         [ +  - ]:          5 :                 metric_vals->maximum_angle = (double)sides[2].interior_angle( sides[1] );
     855         [ +  + ]:         13 :             else if( long_side == 1 )
     856         [ +  - ]:          4 :                 metric_vals->maximum_angle = (double)sides[0].interior_angle( sides[2] );
     857                 :            :             else
     858 [ +  - ][ +  - ]:         18 :                 metric_vals->maximum_angle = (double)sides[0].interior_angle( -sides[1] );
     859                 :            :         }
     860                 :            :     }
     861                 :            : 
     862                 :            :     // calculate the area of the tri
     863                 :            :     // the following metrics depend on area
     864         [ +  - ]:         18 :     if( metrics_request_flag &
     865                 :            :         ( V_TRI_AREA | V_TRI_SCALED_JACOBIAN | V_TRI_SHAPE | V_TRI_RELATIVE_SIZE_SQUARED | V_TRI_SHAPE_AND_SIZE ) )
     866 [ +  - ][ +  - ]:         18 :     { metric_vals->area = (double)( ( sides[0] * sides[2] ).length() * 0.5 ); }
     867                 :            : 
     868                 :            :     // calculate the aspect ratio
     869         [ +  - ]:         18 :     if( metrics_request_flag & V_TRI_ASPECT_FROBENIUS )
     870                 :            :     {
     871                 :            :         // sum the lengths squared
     872                 :         18 :         double srms = sides_lengths_squared[0] + sides_lengths_squared[1] + sides_lengths_squared[2];
     873                 :            : 
     874                 :            :         // calculate once and reuse
     875                 :            :         static const double twoTimesRootOf3 = 2 * sqrt( 3.0 );
     876                 :            : 
     877 [ +  - ][ +  - ]:         18 :         double div = ( twoTimesRootOf3 * ( ( sides[0] * sides[2] ).length() ) );
     878                 :            : 
     879         [ -  + ]:         18 :         if( div == 0.0 )
     880                 :          0 :             metric_vals->aspect_frobenius = (double)VERDICT_DBL_MAX;
     881                 :            :         else
     882                 :         18 :             metric_vals->aspect_frobenius = (double)( srms / div );
     883                 :            :     }
     884                 :            : 
     885                 :            :     // calculate the scaled jacobian
     886         [ +  - ]:         18 :     if( metrics_request_flag & V_TRI_SCALED_JACOBIAN )
     887                 :            :     {
     888                 :            :         // calculate once and reuse
     889                 :            :         static const double twoOverRootOf3 = 2 / sqrt( 3.0 );
     890                 :            :         // use the area from above
     891                 :            : 
     892         [ +  - ]:         18 :         double tmp = tri_normal.length() * twoOverRootOf3;
     893                 :            : 
     894                 :            :         // now scale it by the lengths of the sides
     895                 :         18 :         double min_scaled_jac = VERDICT_DBL_MAX;
     896                 :            :         double temp_scaled_jac;
     897         [ +  + ]:         72 :         for( int i = 0; i < 3; i++ )
     898                 :            :         {
     899 [ +  - ][ -  + ]:         54 :             if( sides_lengths_squared[i % 3] == 0.0 || sides_lengths_squared[( i + 2 ) % 3] == 0.0 )
     900                 :          0 :                 temp_scaled_jac = 0.0;
     901                 :            :             else
     902                 :            :                 temp_scaled_jac =
     903                 :         54 :                     tmp / sqrt( sides_lengths_squared[i % 3] ) / sqrt( sides_lengths_squared[( i + 2 ) % 3] );
     904         [ +  + ]:         54 :             if( temp_scaled_jac < min_scaled_jac ) min_scaled_jac = temp_scaled_jac;
     905                 :            :         }
     906                 :            :         // multiply by -1 if the normals are in opposite directions
     907         [ -  + ]:         18 :         if( is_inverted ) { min_scaled_jac *= -1; }
     908                 :         18 :         metric_vals->scaled_jacobian = (double)min_scaled_jac;
     909                 :            :     }
     910                 :            : 
     911                 :            :     // calculate the condition number
     912         [ +  - ]:         18 :     if( metrics_request_flag & V_TRI_CONDITION )
     913                 :            :     {
     914                 :            :         // calculate once and reuse
     915                 :            :         static const double rootOf3 = sqrt( 3.0 );
     916                 :            :         // if it is inverted, the condition number is considered to be infinity.
     917         [ -  + ]:         18 :         if( is_inverted ) { metric_vals->condition = VERDICT_DBL_MAX; }
     918                 :            :         else
     919                 :            :         {
     920 [ +  - ][ +  - ]:         18 :             double area2x = ( sides[0] * sides[2] ).length();
     921         [ -  + ]:         18 :             if( area2x == 0.0 )
     922                 :          0 :                 metric_vals->condition = (double)( VERDICT_DBL_MAX );
     923                 :            :             else
     924 [ +  - ][ +  - ]:         18 :                 metric_vals->condition = (double)( ( sides[0] % sides[0] + sides[2] % sides[2] - sides[0] % sides[2] ) /
                 [ +  - ]
     925                 :         18 :                                                    ( area2x * rootOf3 ) );
     926                 :            :         }
     927                 :            :     }
     928                 :            : 
     929                 :            :     // calculate the shape
     930 [ -  + ][ #  # ]:         18 :     if( metrics_request_flag & V_TRI_SHAPE || metrics_request_flag & V_TRI_SHAPE_AND_SIZE )
     931                 :            :     {
     932                 :            :         // if element is inverted, shape is zero.  We don't need to
     933                 :            :         // calculate anything.
     934         [ -  + ]:         18 :         if( is_inverted ) { metric_vals->shape = 0.0; }
     935                 :            :         else
     936                 :            :         {  // otherwise, we calculate the shape
     937                 :            :             // calculate once and reuse
     938                 :            :             static const double rootOf3 = sqrt( 3.0 );
     939                 :            :             // reuse area from before
     940                 :         18 :             double area2x = metric_vals->area * 2;
     941                 :            :             // dot products
     942 [ +  - ][ +  - ]:         18 :             double dots[3] = { sides[0] % sides[0], sides[2] % sides[2], sides[0] % sides[2] };
                 [ +  - ]
     943                 :            : 
     944                 :            :             // add the dots
     945                 :         18 :             double sum_dots = dots[0] + dots[1] - dots[2];
     946                 :            : 
     947                 :            :             // then the finale
     948         [ -  + ]:         18 :             if( sum_dots == 0.0 )
     949                 :          0 :                 metric_vals->shape = 0.0;
     950                 :            :             else
     951                 :         18 :                 metric_vals->shape = (double)( rootOf3 * area2x / sum_dots );
     952                 :            :         }
     953                 :            :     }
     954                 :            : 
     955                 :            :     // calculate relative size squared
     956 [ -  + ][ #  # ]:         18 :     if( metrics_request_flag & V_TRI_RELATIVE_SIZE_SQUARED || metrics_request_flag & V_TRI_SHAPE_AND_SIZE )
     957                 :            :     {
     958                 :            :         // get weights
     959                 :            :         double w11, w21, w12, w22;
     960                 :         18 :         v_tri_get_weight( w11, w21, w12, w22 );
     961                 :            :         // get the determinant
     962         [ +  - ]:         18 :         double detw = determinant( w11, w21, w12, w22 );
     963                 :            :         // use the area from above and divide with the determinant
     964 [ +  - ][ -  + ]:         18 :         if( metric_vals->area == 0.0 || detw == 0.0 )
     965                 :          0 :             metric_vals->relative_size_squared = 0.0;
     966                 :            :         else
     967                 :            :         {
     968                 :         18 :             double size = metric_vals->area * 2.0 / detw;
     969                 :            :             // square the size
     970                 :         18 :             size *= size;
     971                 :            :             // value ranges between 0 to 1
     972         [ +  - ]:         18 :             metric_vals->relative_size_squared = (double)VERDICT_MIN( size, 1.0 / size );
     973                 :            :         }
     974                 :            :     }
     975                 :            : 
     976                 :            :     // calculate shape and size
     977         [ +  - ]:         18 :     if( metrics_request_flag & V_TRI_SHAPE_AND_SIZE )
     978                 :         18 :     { metric_vals->shape_and_size = metric_vals->relative_size_squared * metric_vals->shape; }
     979                 :            : 
     980                 :            :     // calculate distortion
     981 [ +  - ][ +  - ]:         18 :     if( metrics_request_flag & V_TRI_DISTORTION ) metric_vals->distortion = v_tri_distortion( num_nodes, coordinates );
     982                 :            : 
     983                 :            :     // take care of any over-flow problems
     984         [ +  - ]:         18 :     if( metric_vals->aspect_frobenius > 0 )
     985         [ +  - ]:         18 :         metric_vals->aspect_frobenius = (double)VERDICT_MIN( metric_vals->aspect_frobenius, VERDICT_DBL_MAX );
     986                 :            :     else
     987         [ #  # ]:          0 :         metric_vals->aspect_frobenius = (double)VERDICT_MAX( metric_vals->aspect_frobenius, -VERDICT_DBL_MAX );
     988                 :            : 
     989         [ +  - ]:         18 :     if( metric_vals->area > 0 )
     990         [ +  - ]:         18 :         metric_vals->area = (double)VERDICT_MIN( metric_vals->area, VERDICT_DBL_MAX );
     991                 :            :     else
     992         [ #  # ]:          0 :         metric_vals->area = (double)VERDICT_MAX( metric_vals->area, -VERDICT_DBL_MAX );
     993                 :            : 
     994         [ +  - ]:         18 :     if( metric_vals->minimum_angle > 0 )
     995         [ +  - ]:         18 :         metric_vals->minimum_angle = (double)VERDICT_MIN( metric_vals->minimum_angle, VERDICT_DBL_MAX );
     996                 :            :     else
     997         [ #  # ]:          0 :         metric_vals->minimum_angle = (double)VERDICT_MAX( metric_vals->minimum_angle, -VERDICT_DBL_MAX );
     998                 :            : 
     999         [ +  - ]:         18 :     if( metric_vals->maximum_angle > 0 )
    1000         [ +  - ]:         18 :         metric_vals->maximum_angle = (double)VERDICT_MIN( metric_vals->maximum_angle, VERDICT_DBL_MAX );
    1001                 :            :     else
    1002         [ #  # ]:          0 :         metric_vals->maximum_angle = (double)VERDICT_MAX( metric_vals->maximum_angle, -VERDICT_DBL_MAX );
    1003                 :            : 
    1004         [ +  - ]:         18 :     if( metric_vals->condition > 0 )
    1005         [ +  - ]:         18 :         metric_vals->condition = (double)VERDICT_MIN( metric_vals->condition, VERDICT_DBL_MAX );
    1006                 :            :     else
    1007         [ #  # ]:          0 :         metric_vals->condition = (double)VERDICT_MAX( metric_vals->condition, -VERDICT_DBL_MAX );
    1008                 :            : 
    1009         [ +  - ]:         18 :     if( metric_vals->shape > 0 )
    1010         [ +  - ]:         18 :         metric_vals->shape = (double)VERDICT_MIN( metric_vals->shape, VERDICT_DBL_MAX );
    1011                 :            :     else
    1012         [ #  # ]:          0 :         metric_vals->shape = (double)VERDICT_MAX( metric_vals->shape, -VERDICT_DBL_MAX );
    1013                 :            : 
    1014         [ +  - ]:         18 :     if( metric_vals->scaled_jacobian > 0 )
    1015         [ +  - ]:         18 :         metric_vals->scaled_jacobian = (double)VERDICT_MIN( metric_vals->scaled_jacobian, VERDICT_DBL_MAX );
    1016                 :            :     else
    1017         [ #  # ]:          0 :         metric_vals->scaled_jacobian = (double)VERDICT_MAX( metric_vals->scaled_jacobian, -VERDICT_DBL_MAX );
    1018                 :            : 
    1019         [ +  - ]:         18 :     if( metric_vals->relative_size_squared > 0 )
    1020         [ +  - ]:         18 :         metric_vals->relative_size_squared = (double)VERDICT_MIN( metric_vals->relative_size_squared, VERDICT_DBL_MAX );
    1021                 :            :     else
    1022                 :            :         metric_vals->relative_size_squared =
    1023         [ #  # ]:          0 :             (double)VERDICT_MAX( metric_vals->relative_size_squared, -VERDICT_DBL_MAX );
    1024                 :            : 
    1025         [ +  - ]:         18 :     if( metric_vals->shape_and_size > 0 )
    1026         [ +  - ]:         18 :         metric_vals->shape_and_size = (double)VERDICT_MIN( metric_vals->shape_and_size, VERDICT_DBL_MAX );
    1027                 :            :     else
    1028         [ #  # ]:          0 :         metric_vals->shape_and_size = (double)VERDICT_MAX( metric_vals->shape_and_size, -VERDICT_DBL_MAX );
    1029                 :            : 
    1030         [ +  - ]:         18 :     if( metric_vals->distortion > 0 )
    1031         [ +  - ]:         18 :         metric_vals->distortion = (double)VERDICT_MIN( metric_vals->distortion, VERDICT_DBL_MAX );
    1032                 :            :     else
    1033         [ #  # ]:          0 :         metric_vals->distortion = (double)VERDICT_MAX( metric_vals->distortion, -VERDICT_DBL_MAX );
    1034                 :            : 
    1035 [ +  - ][ +  - ]:         18 :     if( metrics_request_flag & V_TRI_EDGE_RATIO ) { metric_vals->edge_ratio = v_tri_edge_ratio( 3, coordinates ); }
    1036         [ +  - ]:         18 :     if( metrics_request_flag & V_TRI_RADIUS_RATIO )
    1037         [ +  - ]:         18 :     { metric_vals->radius_ratio = v_tri_radius_ratio( 3, coordinates ); }
    1038         [ +  - ]:         18 :     if( metrics_request_flag & V_TRI_ASPECT_FROBENIUS )  // there is no V_TRI_ASPECT_RATIO !
    1039         [ +  - ]:         18 :     { metric_vals->aspect_ratio = v_tri_radius_ratio( 3, coordinates ); }
    1040                 :         18 : }

Generated by: LCOV version 1.11