/*! warpage of a quad deviation of element from planarity */ C_FUNC_DEF VERDICT_REAL v_quad_warpage( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { VerdictVector edges[4]; make_quad_edges( edges, coordinates ); VerdictVector corner_normals[4]; corner_normals[0] = edges[3] * edges[0]; corner_normals[1] = edges[0] * edges[1]; corner_normals[2] = edges[1] * edges[2]; corner_normals[3] = edges[2] * edges[3]; if( corner_normals[0].normalize() < VERDICT_DBL_MIN || corner_normals[1].normalize() < VERDICT_DBL_MIN || corner_normals[2].normalize() < VERDICT_DBL_MIN || corner_normals[3].normalize() < VERDICT_DBL_MIN ) return (VERDICT_REAL) VERDICT_DBL_MIN; double warpage = pow( VERDICT_MIN( corner_normals[0]%corner_normals[2], corner_normals[1]%corner_normals[3]), 3 ); if( warpage > 0 ) return (VERDICT_REAL) VERDICT_MIN( warpage, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( warpage, -VERDICT_DBL_MAX ); }
/*! taper of a quad maximum ratio of lengths derived from opposite edges */ C_FUNC_DEF VERDICT_REAL v_quad_taper( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { VerdictVector node_pos[4]; for(int i = 0; i < 4; i++ ) node_pos[i].set(coordinates[i][0], coordinates[i][1], coordinates[i][2]); VerdictVector principle_axes[2]; principle_axes[0] = node_pos[1] + node_pos[2] - node_pos[3] - node_pos[0]; principle_axes[1] = node_pos[2] + node_pos[3] - node_pos[0] - node_pos[1]; VerdictVector cross_derivative = node_pos[0] + node_pos[2] - node_pos[1] - node_pos[3]; double lengths[2]; lengths[0] = principle_axes[0].length(); lengths[1] = principle_axes[1].length(); //get min length lengths[0] = VERDICT_MIN( lengths[0], lengths[1] ); if( lengths[0] < VERDICT_DBL_MIN ) return VERDICT_DBL_MAX; double taper = cross_derivative.length()/ lengths[0]; return (VERDICT_REAL) VERDICT_MIN( taper, VERDICT_DBL_MAX ); }
/*! the relative size of a quad Min( J, 1/J ), where J is determinant of weighted Jacobian matrix */ C_FUNC_DEF VERDICT_REAL v_quad_relative_size_squared( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { double quad_area = v_quad_area (4, coordinates); double rel_size = 0; v_set_quad_size( quad_area ); double w11,w21,w12,w22; get_weight(w11,w21,w12,w22); double avg_area = determinant(w11,w21,w12,w22); if ( avg_area > VERDICT_DBL_MIN ) { w11 = quad_area / avg_area; if ( w11 > VERDICT_DBL_MIN ) { rel_size = VERDICT_MIN( w11, 1/w11 ); rel_size *= rel_size; } } if( rel_size > 0 ) return (VERDICT_REAL) VERDICT_MIN( rel_size, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( rel_size, -VERDICT_DBL_MAX ); }
/*! The minimum angle of a tri The minimum angle of a tri is the minimum angle between two adjacents sides out of all three corners of the triangle. */ C_FUNC_DEF VERDICT_REAL v_tri_minimum_angle( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { // vectors for all the sides VerdictVector sides[4]; sides[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); sides[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2] ); sides[2].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1], coordinates[2][2] - coordinates[0][2] ); // in case we need to find the interior angle // between sides 0 and 1 sides[3] = -sides[1]; // calculate the lengths squared of the sides double sides_lengths[3]; sides_lengths[0] = sides[0].length_squared(); sides_lengths[1] = sides[1].length_squared(); sides_lengths[2] = sides[2].length_squared(); if(sides_lengths[0] == 0.0 || sides_lengths[1] == 0.0 || sides_lengths[2] == 0.0) return 0.0; // using the law of sines, we know that the minimum // angle is opposite of the shortest side // find the shortest side int short_side=0; if(sides_lengths[1] < sides_lengths[0]) short_side = 1; if(sides_lengths[2] < sides_lengths[short_side]) short_side = 2; // from the shortest side, calculate the angle of the // opposite angle double min_angle = 0.; if(short_side == 0) min_angle = sides[2].interior_angle(sides[1]); else if(short_side == 1) min_angle = sides[0].interior_angle(sides[2]); else min_angle = sides[0].interior_angle(sides[3]); if( min_angle > 0 ) return (VERDICT_REAL) VERDICT_MIN( min_angle, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( min_angle, -VERDICT_DBL_MAX ); }
/*! the jacobian of a quad minimum pointwise volume of local map at 4 corners and center of quad */ C_FUNC_DEF VERDICT_REAL v_quad_jacobian( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { if ( is_collapsed_quad( coordinates ) == VERDICT_TRUE ) return (VERDICT_REAL)(v_tri_area(3, coordinates) * 2.0); double areas[4]; signed_corner_areas( areas, coordinates ); double jacobian = VERDICT_MIN( VERDICT_MIN( areas[0], areas[1] ), VERDICT_MIN( areas[2], areas[3] ) ); if( jacobian > 0 ) return (VERDICT_REAL) VERDICT_MIN( jacobian, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( jacobian, -VERDICT_DBL_MAX ); }
C_FUNC_DEF double v_tri_aspect_frobenius( int /*num_nodes*/, double coordinates[][3] ) { static const double two_times_root_of_3 = 2*sqrt(3.0); // three vectors for each side VerdictVector side1( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); VerdictVector side2( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2] ); VerdictVector side3( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1], coordinates[0][2] - coordinates[2][2] ); //sum the lengths squared of each side double srms = (side1.length_squared() + side2.length_squared() + side3.length_squared()); // find two times the area of the triangle by cross product double areaX2 = ((side1 * (-side3)).length()); if(areaX2 == 0.0) return (double)VERDICT_DBL_MAX; double aspect = (double)(srms / (two_times_root_of_3 * (areaX2))); if( aspect > 0 ) return (double) VERDICT_MIN( aspect, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( aspect, -VERDICT_DBL_MAX ); }
/*! the radius ratio of a triangle NB (P. Pebay 01/13/07): CR / (2.0*IR) where CR is the circumradius and IR is the inradius The radius ratio is also known to VERDICT, for tetrahedral elements only, as the "aspect beta". */ C_FUNC_DEF double v_tri_radius_ratio( int /*num_nodes*/, double coordinates[][3] ) { // three vectors for each side VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2] ); VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1], coordinates[0][2] - coordinates[2][2] ); double a1 = a.length(); double b1 = b.length(); double c1 = c.length(); VerdictVector ab = a * b; double denominator = ab.length_squared(); if( denominator < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX; double radius_ratio; radius_ratio = .25 * a1 * b1 * c1 * ( a1 + b1 + c1 ) / denominator; if( radius_ratio > 0 ) return (double) VERDICT_MIN( radius_ratio, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( radius_ratio, -VERDICT_DBL_MAX ); }
/*! the shear of a quad 2/Condition number of Jacobian Skew matrix */ C_FUNC_DEF VERDICT_REAL v_quad_shear( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { double scaled_jacobian = v_quad_scaled_jacobian( 4, coordinates ); if( scaled_jacobian <= VERDICT_DBL_MIN ) return 0.0; else return (VERDICT_REAL) VERDICT_MIN( scaled_jacobian, VERDICT_DBL_MAX ); }
/*! The scaled jacobian of a tri minimum of the jacobian divided by the lengths of 2 edge vectors */ C_FUNC_DEF double v_tri_scaled_jacobian( int /*num_nodes*/, double coordinates[][3]) { static const double detw = 2./sqrt(3.0); VerdictVector first, second; double jacobian; VerdictVector edge[3]; edge[0].set(coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2]); edge[1].set(coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1], coordinates[2][2] - coordinates[0][2]); edge[2].set(coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2]); first = edge[1]-edge[0]; second = edge[2]-edge[0]; VerdictVector cross = first * second; jacobian = cross.length(); double max_edge_length_product; max_edge_length_product = VERDICT_MAX( edge[0].length()*edge[1].length(), VERDICT_MAX( edge[1].length()*edge[2].length(), edge[0].length()*edge[2].length() ) ); if( max_edge_length_product < VERDICT_DBL_MIN ) return (double)0.0; jacobian *= detw; jacobian /= max_edge_length_product; if( compute_normal ) { //center of tri double point[3], surf_normal[3]; point[0] = (coordinates[0][0] + coordinates[1][0] + coordinates[2][0]) / 3; point[1] = (coordinates[0][1] + coordinates[1][1] + coordinates[2][1]) / 3; point[2] = (coordinates[0][2] + coordinates[1][2] + coordinates[2][2]) / 3; //dot product compute_normal( point, surf_normal ); if( (cross.x()*surf_normal[0] + cross.y()*surf_normal[1] + cross.z()*surf_normal[2] ) < 0 ) jacobian *= -1; } if( jacobian > 0 ) return (double) VERDICT_MIN( jacobian, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( jacobian, -VERDICT_DBL_MAX ); }
/*! the shape of a quad 2/Condition number of weighted Jacobian matrix */ C_FUNC_DEF VERDICT_REAL v_quad_shape( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { double corner_areas[4], min_shape = VERDICT_DBL_MAX, shape; signed_corner_areas( corner_areas, coordinates ); VerdictVector edges[4]; make_quad_edges( edges, coordinates ); double length_squared[4]; length_squared[0] = edges[0].length_squared(); length_squared[1] = edges[1].length_squared(); length_squared[2] = edges[2].length_squared(); length_squared[3] = edges[3].length_squared(); if( length_squared[0] <= VERDICT_DBL_MIN || length_squared[1] <= VERDICT_DBL_MIN || length_squared[2] <= VERDICT_DBL_MIN || length_squared[3] <= VERDICT_DBL_MIN ) return 0.0; shape = corner_areas[0] / (length_squared[0] + length_squared[3]); min_shape = VERDICT_MIN( shape, min_shape ); shape = corner_areas[1] / (length_squared[1] + length_squared[0]); min_shape = VERDICT_MIN( shape, min_shape ); shape = corner_areas[2] / (length_squared[2] + length_squared[1]); min_shape = VERDICT_MIN( shape, min_shape ); shape = corner_areas[3] / (length_squared[3] + length_squared[2]); min_shape = VERDICT_MIN( shape, min_shape ); min_shape *= 2; if( min_shape < VERDICT_DBL_MIN ) min_shape = 0; if( min_shape > 0 ) return (VERDICT_REAL) VERDICT_MIN( min_shape, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( min_shape, -VERDICT_DBL_MAX ); }
/*! the aspect of a tet CR / (3.0*IR) where CR is the circumsphere radius and IR is the inscribed sphere radius */ C_FUNC_DEF VERDICT_REAL v_tet_aspect_beta( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { //Determine side vectors VerdictVector side[6]; side[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); side[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2] ); side[2].set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1], coordinates[0][2] - coordinates[2][2] ); side[3].set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1], coordinates[3][2] - coordinates[0][2] ); side[4].set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1], coordinates[3][2] - coordinates[1][2] ); side[5].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1], coordinates[3][2] - coordinates[2][2] ); VerdictVector numerator = side[3].length_squared() * ( side[2] * side[0]) + side[2].length_squared() * ( side[3] * side[0]) + side[0].length_squared() * ( side[3] * side[2]); double area_sum = 0.0; area_sum = ((side[2] * side[0]).length() + (side[3] * side[0]).length() + (side[4] * side[1]).length() + (side[3] * side[2]).length() ) * 0.5; double volume = v_tet_volume(4, coordinates); if( volume < VERDICT_DBL_MIN ) return (VERDICT_REAL)VERDICT_DBL_MAX; else { double aspect_ratio; aspect_ratio = numerator.length() * area_sum / (108*volume*volume); if( aspect_ratio > 0 ) return (VERDICT_REAL) VERDICT_MIN( aspect_ratio, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( aspect_ratio, -VERDICT_DBL_MAX ); } }
/*! scaled jacobian of a quad Minimum Jacobian divided by the lengths of the 2 edge vector */ C_FUNC_DEF VERDICT_REAL v_quad_scaled_jacobian( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { if ( is_collapsed_quad( coordinates ) == VERDICT_TRUE ) return v_tri_scaled_jacobian(3, coordinates); double corner_areas[4], min_scaled_jac = VERDICT_DBL_MAX, scaled_jac; signed_corner_areas( corner_areas, coordinates ); VerdictVector edges[4]; make_quad_edges( edges, coordinates ); double length[4]; length[0] = edges[0].length(); length[1] = edges[1].length(); length[2] = edges[2].length(); length[3] = edges[3].length(); if( length[0] < VERDICT_DBL_MIN || length[1] < VERDICT_DBL_MIN || length[2] < VERDICT_DBL_MIN || length[3] < VERDICT_DBL_MIN ) return 0.0; scaled_jac = corner_areas[0] / (length[0] * length[3]); min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac ); scaled_jac = corner_areas[1] / (length[1] * length[0]); min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac ); scaled_jac = corner_areas[2] / (length[2] * length[1]); min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac ); scaled_jac = corner_areas[3] / (length[3] * length[2]); min_scaled_jac = VERDICT_MIN( scaled_jac, min_scaled_jac ); if( min_scaled_jac > 0 ) return (VERDICT_REAL) VERDICT_MIN( min_scaled_jac, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( min_scaled_jac, -VERDICT_DBL_MAX ); }
/*! the shear and size of a quad product of shear and relative size */ C_FUNC_DEF VERDICT_REAL v_quad_shear_and_size( int num_nodes, VERDICT_REAL coordinates[][3] ) { double shear, size; shear = v_quad_shear( num_nodes, coordinates ); size = v_quad_relative_size_squared( num_nodes, coordinates ); double shear_and_size = shear * size; if( shear_and_size > 0 ) return (VERDICT_REAL) VERDICT_MIN( shear_and_size, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( shear_and_size, -VERDICT_DBL_MAX ); }
/*! the stretch of a quad sqrt(2) * minimum edge length / maximum diagonal length */ C_FUNC_DEF VERDICT_REAL v_quad_stretch( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { VerdictVector edges[4], temp; make_quad_edges( edges, coordinates ); double lengths_squared[4]; lengths_squared[0] = edges[0].length(); lengths_squared[1] = edges[1].length(); lengths_squared[2] = edges[2].length(); lengths_squared[3] = edges[3].length(); temp.set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1], coordinates[2][2] - coordinates[0][2]); double diag02 = temp.length_squared(); temp.set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1], coordinates[3][2] - coordinates[1][2]); double diag13 = temp.length_squared(); static const double QUAD_STRETCH_FACTOR = sqrt(2.0); // 'diag02' is now the max diagonal of the quad diag02 = VERDICT_MAX( diag02, diag13 ); if( diag02 < VERDICT_DBL_MIN ) return (VERDICT_REAL) VERDICT_DBL_MAX; else { double stretch = (VERDICT_REAL) ( QUAD_STRETCH_FACTOR * sqrt( VERDICT_MIN( VERDICT_MIN( lengths_squared[0], lengths_squared[1] ), VERDICT_MIN( lengths_squared[2], lengths_squared[3] ) ) / diag02 )); return (VERDICT_REAL) VERDICT_MIN( stretch, VERDICT_DBL_MAX ); } }
/*! the area of a quad jacobian at quad center */ C_FUNC_DEF VERDICT_REAL v_quad_area( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { double corner_areas[4]; signed_corner_areas( corner_areas, coordinates ); double area = 0.25 * (corner_areas[0] + corner_areas[1] + corner_areas[2] + corner_areas[3]); if( area > 0 ) return (VERDICT_REAL) VERDICT_MIN( area, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( area, -VERDICT_DBL_MAX ); }
/*! The shape and size of a tri Product of the Shape and Relative Size */ C_FUNC_DEF double v_tri_shape_and_size( int num_nodes, double coordinates[][3] ) { double size, shape; size = v_tri_relative_size_squared( num_nodes, coordinates ); shape = v_tri_shape( num_nodes, coordinates ); double shape_and_size = size * shape; if( shape_and_size > 0 ) return (double) VERDICT_MIN( shape_and_size, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( shape_and_size, -VERDICT_DBL_MAX ); }
/*! The shape of a tri 2 / condition number of weighted jacobian matrix */ C_FUNC_DEF double v_tri_shape( int num_nodes, double coordinates[][3] ) { double condition = v_tri_condition( num_nodes, coordinates ); double shape; if( condition <= VERDICT_DBL_MIN ) shape = VERDICT_DBL_MAX; else shape = (1 / condition); if( shape > 0 ) return (double) VERDICT_MIN( shape, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( shape, -VERDICT_DBL_MAX ); }
/*! The relative size of a tri Min(J,1/J) where J is the determinant of the weighted jacobian matrix. */ C_FUNC_DEF double v_tri_relative_size_squared( int /*num_nodes*/, double coordinates[][3] ) { double w11, w21, w12, w22; VerdictVector xxi, xet, tri_normal; v_tri_get_weight(w11,w21,w12,w22); double detw = v_determinant(w11,w21,w12,w22); if(detw == 0.0) return 0.0; xxi.set(coordinates[0][0] - coordinates[1][0], coordinates[0][1] - coordinates[1][1], coordinates[0][2] - coordinates[1][2]); xet.set(coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1], coordinates[0][2] - coordinates[2][2]); tri_normal = xxi * xet; double deta = tri_normal.length(); if( deta == 0.0 || detw == 0.0 ) return 0.0; double size = pow( deta/detw, 2 ); double rel_size = VERDICT_MIN(size, 1.0/size ); if( rel_size > 0 ) return (double) VERDICT_MIN( rel_size, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( rel_size, -VERDICT_DBL_MAX ); }
/*! skew of a quad maximum ||cos A|| where A is the angle between edges at quad center */ C_FUNC_DEF VERDICT_REAL v_quad_skew( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { VerdictVector node_pos[4]; for(int i = 0; i < 4; i++ ) node_pos[i].set(coordinates[i][0], coordinates[i][1], coordinates[i][2]); VerdictVector principle_axes[2]; principle_axes[0] = node_pos[1] + node_pos[2] - node_pos[3] - node_pos[0]; principle_axes[1] = node_pos[2] + node_pos[3] - node_pos[0] - node_pos[1]; if( principle_axes[0].normalize() < VERDICT_DBL_MIN ) return 0.0; if( principle_axes[1].normalize() < VERDICT_DBL_MIN ) return 0.0; double skew = fabs( principle_axes[0] % principle_axes[1] ); return (VERDICT_REAL) VERDICT_MIN( skew, VERDICT_DBL_MAX ); }
/*! The condition of a tri Condition number of the jacobian matrix at any corner */ C_FUNC_DEF VERDICT_REAL v_tri_condition( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { static const double rt3 = sqrt(3.0); VerdictVector v1(coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); VerdictVector v2(coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1], coordinates[2][2] - coordinates[0][2] ); VerdictVector tri_normal = v1 * v2; double areax2= tri_normal.length(); if (areax2 == 0.0 ) return (VERDICT_REAL)VERDICT_DBL_MAX; double condition = (VERDICT_REAL)( ((v1%v1) + (v2%v2) - (v1%v2)) / (areax2*rt3) ); return (VERDICT_REAL)VERDICT_MIN( condition, VERDICT_DBL_MAX ); }
/*! the condition of a quad maximum condition number of the Jacobian matrix at 4 corners */ C_FUNC_DEF VERDICT_REAL v_quad_condition( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { if ( is_collapsed_quad( coordinates ) == VERDICT_TRUE ) return v_tri_condition(3,coordinates); double areas[4]; signed_corner_areas( areas, coordinates ); double max_condition = 0.; VerdictVector xxi, xet; double condition; for ( int i=0; i<4; i++ ) { xxi.set( coordinates[i][0] - coordinates[(i+1)%4][0], coordinates[i][1] - coordinates[(i+1)%4][1], coordinates[i][2] - coordinates[(i+1)%4][2] ); xet.set( coordinates[i][0] - coordinates[(i+3)%4][0], coordinates[i][1] - coordinates[(i+3)%4][1], coordinates[i][2] - coordinates[(i+3)%4][2] ); if ( areas[i] < VERDICT_DBL_MIN ) condition = VERDICT_DBL_MAX; else condition = ( xxi % xxi + xet % xet ) / areas[i]; max_condition = VERDICT_MAX(max_condition, condition); } max_condition /= 2; if( max_condition > 0 ) return (VERDICT_REAL) VERDICT_MIN( max_condition, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( max_condition, -VERDICT_DBL_MAX ); }
/*! the aspect ratio of a triangle NB (P. Pebay 01/14/07): Hmax / ( 2.0 * sqrt(3.0) * IR) where Hmax is the maximum edge length and IR is the inradius note that previous incarnations of verdict used "v_tri_aspect_ratio" to denote what is now called "v_tri_aspect_frobenius" */ C_FUNC_DEF double v_tri_aspect_ratio( int /*num_nodes*/, double coordinates[][3] ) { static const double normal_coeff = sqrt( 3. ) / 6.; // three vectors for each side VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2] ); VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1], coordinates[0][2] - coordinates[2][2] ); double a1 = a.length(); double b1 = b.length(); double c1 = c.length(); double hm = a1 > b1 ? a1 : b1; hm = hm > c1 ? hm : c1; VerdictVector ab = a * b; double denominator = ab.length(); if( denominator < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX; else { double aspect_ratio; aspect_ratio = normal_coeff * hm * (a1 + b1 + c1) / denominator; if( aspect_ratio > 0 ) return (double) VERDICT_MIN( aspect_ratio, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( aspect_ratio, -VERDICT_DBL_MAX ); } }
/*! The area of a tri 0.5 * jacobian at a node */ C_FUNC_DEF double v_tri_area( int /*num_nodes*/, double coordinates[][3] ) { // two vectors for two sides VerdictVector side1( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); VerdictVector side3( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1], coordinates[2][2] - coordinates[0][2] ); // the cross product of the two vectors representing two sides of the // triangle VerdictVector tmp = side1 * side3; // return the magnitude of the vector divided by two double area = 0.5 * tmp.length(); if( area > 0 ) return (double) VERDICT_MIN( area, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( area, -VERDICT_DBL_MAX ); }
/*! The condition of a tri Condition number of the jacobian matrix at any corner */ C_FUNC_DEF double v_tri_condition( int /*num_nodes*/, double coordinates[][3] ) { static const double rt3 = sqrt(3.0); VerdictVector v1(coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); VerdictVector v2(coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1], coordinates[2][2] - coordinates[0][2] ); VerdictVector tri_normal = v1 * v2; double areax2= tri_normal.length(); if (areax2 == 0.0 ) return (double)VERDICT_DBL_MAX; double condition = (double)( ((v1%v1) + (v2%v2) - (v1%v2)) / (areax2*rt3) ); //check for inverted if we have access to the normal if( compute_normal ) { //center of tri double point[3], surf_normal[3]; point[0] = (coordinates[0][0] + coordinates[1][0] + coordinates[2][0]) / 3; point[1] = (coordinates[0][1] + coordinates[1][1] + coordinates[2][1]) / 3; point[2] = (coordinates[0][2] + coordinates[1][2] + coordinates[2][2]) / 3; //dot product compute_normal( point, surf_normal ); if( (tri_normal.x()*surf_normal[0] + tri_normal.y()*surf_normal[1] + tri_normal.z()*surf_normal[2] ) < 0 ) return (double)VERDICT_DBL_MAX; } return (double)VERDICT_MIN( condition, VERDICT_DBL_MAX ); }
/*! the oddy of a quad general distortion measure based on left Cauchy-Green Tensor */ C_FUNC_DEF VERDICT_REAL v_quad_oddy( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { double max_oddy = 0.; VerdictVector first, second, node_pos[4]; double g, g11, g12, g22, cur_oddy; int i; for(i = 0; i < 4; i++ ) node_pos[i].set(coordinates[i][0], coordinates[i][1], coordinates[i][2]); for ( i = 0; i < 4; i++ ) { first = node_pos[i] - node_pos[(i+1)%4]; second = node_pos[i] - node_pos[(i+3)%4]; g11 = first % first; g12 = first % second; g22 = second % second; g = g11*g22 - g12*g12; if ( g < VERDICT_DBL_MIN ) cur_oddy = VERDICT_DBL_MAX; else cur_oddy = ( (g11-g22)*(g11-g22) + 4.*g12*g12 ) / 2. / g; max_oddy = VERDICT_MAX(max_oddy, cur_oddy); } if( max_oddy > 0 ) return (VERDICT_REAL) VERDICT_MIN( max_oddy, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( max_oddy, -VERDICT_DBL_MAX ); }
/*! aspect ratio of a quad maximum edge length ratios at quad center */ C_FUNC_DEF VERDICT_REAL v_quad_aspect( int /*num_nodes*/, VERDICT_REAL coordinates[][3] ) { VerdictVector quad_nodes[4]; quad_nodes[0].set( coordinates[0][0], coordinates[0][1], coordinates[0][2] ); quad_nodes[1].set( coordinates[1][0], coordinates[1][1], coordinates[1][2] ); quad_nodes[2].set( coordinates[2][0], coordinates[2][1], coordinates[2][2] ); quad_nodes[3].set( coordinates[3][0], coordinates[3][1], coordinates[3][2] ); VerdictVector principal_axes[2]; principal_axes[0] = quad_nodes[1] + quad_nodes[2] - quad_nodes[0] - quad_nodes[3]; principal_axes[1] = quad_nodes[2] + quad_nodes[3] - quad_nodes[0] - quad_nodes[1]; double len1 = principal_axes[0].length(); double len2 = principal_axes[1].length(); if( len1 < VERDICT_DBL_MIN || len2 < VERDICT_DBL_MIN ) return (VERDICT_REAL)VERDICT_DBL_MAX; double aspect = VERDICT_MAX( len1 / len2, len2 / len1 ); if( aspect > 0 ) return (VERDICT_REAL) VERDICT_MIN( aspect, VERDICT_DBL_MAX ); return (VERDICT_REAL) VERDICT_MAX( aspect, -VERDICT_DBL_MAX ); }
/*! the quality metrics of a tet */ C_FUNC_DEF void v_tet_quality( int num_nodes, VERDICT_REAL coordinates[][3], unsigned int metrics_request_flag, TetMetricVals *metric_vals ) { memset( metric_vals, 0, sizeof(TetMetricVals) ); /* node numbers and edge numbers below 3 + edge 0 is node 0 to 1 +|+ edge 1 is node 1 to 2 3/ | \5 edge 2 is node 0 to 2 / 4| \ edge 3 is node 0 to 3 0 - -|- + 2 edge 4 is node 1 to 3 \ | + edge 5 is node 2 to 3 0\ | /1 +|/ edge 2 is behind edge 4 1 */ // lets start with making the vectors VerdictVector edges[6]; edges[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); edges[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2] ); edges[2].set( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1], coordinates[0][2] - coordinates[2][2] ); edges[3].set( coordinates[3][0] - coordinates[0][0], coordinates[3][1] - coordinates[0][1], coordinates[3][2] - coordinates[0][2] ); edges[4].set( coordinates[3][0] - coordinates[1][0], coordinates[3][1] - coordinates[1][1], coordinates[3][2] - coordinates[1][2] ); edges[5].set( coordinates[3][0] - coordinates[2][0], coordinates[3][1] - coordinates[2][1], coordinates[3][2] - coordinates[2][2] ); // common numbers static const double root_of_2 = sqrt(2.0); // calculate the jacobian static const int do_jacobian = V_TET_JACOBIAN | V_TET_VOLUME | V_TET_ASPECT_BETA | V_TET_ASPECT_GAMMA | V_TET_SHAPE | V_TET_RELATIVE_SIZE_SQUARED | V_TET_SHAPE_AND_SIZE | V_TET_SCALED_JACOBIAN | V_TET_CONDITION; if(metrics_request_flag & do_jacobian ) { metric_vals->jacobian = (VERDICT_REAL)(edges[3] % (edges[2] * edges[0])); } // calculate the volume if(metrics_request_flag & V_TET_VOLUME) { metric_vals->volume = (VERDICT_REAL)(metric_vals->jacobian / 6.0); } // calculate aspect ratio if(metrics_request_flag & V_TET_ASPECT_BETA) { double surface_area = ((edges[2] * edges[0]).length() + (edges[3] * edges[0]).length() + (edges[4] * edges[1]).length() + (edges[3] * edges[2]).length() ) * 0.5; VerdictVector numerator = edges[3].length_squared() * ( edges[2] * edges[0] ) + edges[2].length_squared() * ( edges[3] * edges[0] ) + edges[0].length_squared() * ( edges[3] * edges[2] ); double volume = metric_vals->jacobian / 6.0; if(volume < VERDICT_DBL_MIN ) metric_vals->aspect_beta = (VERDICT_REAL)(VERDICT_DBL_MAX); else metric_vals->aspect_beta = (VERDICT_REAL)( numerator.length() * surface_area/ (108*volume*volume) ); } // calculate the aspect gamma if(metrics_request_flag & V_TET_ASPECT_GAMMA) { double volume = fabs( metric_vals->jacobian / 6.0 ); if( fabs( volume ) < VERDICT_DBL_MIN ) metric_vals->aspect_gamma = VERDICT_DBL_MAX; else { double srms = sqrt(( edges[0].length_squared() + edges[1].length_squared() + edges[2].length_squared() + edges[3].length_squared() + edges[4].length_squared() + edges[5].length_squared() ) / 6.0 ); // cube the srms srms *= (srms * srms); metric_vals->aspect_gamma = (VERDICT_REAL)( srms / (8.47967 * volume )); } } // calculate the shape of the tet if(metrics_request_flag & ( V_TET_SHAPE | V_TET_SHAPE_AND_SIZE ) ) { static const double two_thirds = 2.0/3.0; double num = 3.0 * pow(root_of_2 * metric_vals->jacobian, two_thirds); double den = 1.5 * (edges[0] % edges[0] + edges[2] % edges[2] + edges[3] % edges[3]) - (edges[0] % -edges[2] + -edges[2] % edges[3] + edges[3] % edges[0]); if( den < VERDICT_DBL_MIN ) metric_vals->shape = (VERDICT_REAL)0.0; else metric_vals->shape = (VERDICT_REAL)VERDICT_MAX( num/den, 0 ); } // calculate the relative size of the tet if(metrics_request_flag & (V_TET_RELATIVE_SIZE_SQUARED | V_TET_SHAPE_AND_SIZE )) { VerdictVector w1, w2, w3; get_weight(w1,w2,w3); double avg_vol = (w1 % (w2 *w3))/6; if( avg_vol < VERDICT_DBL_MIN ) metric_vals->relative_size_squared = 0.0; else { double tmp = metric_vals->jacobian / (6*avg_vol); if( tmp < VERDICT_DBL_MIN ) metric_vals->relative_size_squared = 0.0; else { tmp *= tmp; metric_vals->relative_size_squared = (VERDICT_REAL)VERDICT_MIN(tmp, 1/tmp); } } } // calculate the shape and size if(metrics_request_flag & V_TET_SHAPE_AND_SIZE) { metric_vals->shape_and_size = (VERDICT_REAL)(metric_vals->shape * metric_vals->relative_size_squared); } // calculate the scaled jacobian if(metrics_request_flag & V_TET_SCALED_JACOBIAN) { //find out which node the normalized jacobian can be calculated at //and it will be the smaller than at other nodes double length_squared[4] = { edges[0].length_squared() * edges[2].length_squared() * edges[3].length_squared(), edges[0].length_squared() * edges[1].length_squared() * edges[4].length_squared(), edges[1].length_squared() * edges[2].length_squared() * edges[5].length_squared(), edges[3].length_squared() * edges[4].length_squared() * edges[5].length_squared() }; int which_node = 0; if(length_squared[1] > length_squared[which_node]) which_node = 1; if(length_squared[2] > length_squared[which_node]) which_node = 2; if(length_squared[3] > length_squared[which_node]) which_node = 3; // find the scaled jacobian at this node double length_product = sqrt( length_squared[which_node] ); if(length_product < fabs(metric_vals->jacobian)) length_product = fabs(metric_vals->jacobian); if( length_product < VERDICT_DBL_MIN ) metric_vals->scaled_jacobian = (VERDICT_REAL) VERDICT_DBL_MAX; else metric_vals->scaled_jacobian = (VERDICT_REAL)(root_of_2 * metric_vals->jacobian / length_product); } // calculate the condition number if(metrics_request_flag & V_TET_CONDITION) { static const double root_of_3 = sqrt(3.0); static const double root_of_6 = sqrt(6.0); VerdictVector c_1, c_2, c_3; c_1 = edges[0]; c_2 = (-2*edges[2] - edges[0])/root_of_3; c_3 = (3*edges[3] + edges[2] - edges[0])/root_of_6; double term1 = c_1 % c_1 + c_2 % c_2 + c_3 % c_3; double term2 = ( c_1 * c_2 ) % ( c_1 * c_2 ) + ( c_2 * c_3 ) % ( c_2 * c_3 ) + ( c_3 * c_1 ) % ( c_3 * c_1 ); double det = c_1 % ( c_2 * c_3 ); if(det <= VERDICT_DBL_MIN) metric_vals->condition = (VERDICT_REAL)VERDICT_DBL_MAX; else metric_vals->condition = (VERDICT_REAL)(sqrt(term1 * term2) / (3.0*det)); } // calculate the distortion if(metrics_request_flag & V_TET_DISTORTION) { metric_vals->distortion = v_tet_distortion(num_nodes, coordinates); } //check for overflow if(metrics_request_flag & V_TET_ASPECT_BETA ) { if( metric_vals->aspect_beta > 0 ) metric_vals->aspect_beta = (VERDICT_REAL) VERDICT_MIN( metric_vals->aspect_beta, VERDICT_DBL_MAX ); metric_vals->aspect_beta = (VERDICT_REAL) VERDICT_MAX( metric_vals->aspect_beta, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_ASPECT_GAMMA) { if( metric_vals->aspect_gamma > 0 ) metric_vals->aspect_gamma = (VERDICT_REAL) VERDICT_MIN( metric_vals->aspect_gamma, VERDICT_DBL_MAX ); metric_vals->aspect_gamma = (VERDICT_REAL) VERDICT_MAX( metric_vals->aspect_gamma, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_VOLUME) { if( metric_vals->volume > 0 ) metric_vals->volume = (VERDICT_REAL) VERDICT_MIN( metric_vals->volume, VERDICT_DBL_MAX ); metric_vals->volume = (VERDICT_REAL) VERDICT_MAX( metric_vals->volume, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_CONDITION) { if( metric_vals->condition > 0 ) metric_vals->condition = (VERDICT_REAL) VERDICT_MIN( metric_vals->condition, VERDICT_DBL_MAX ); metric_vals->condition = (VERDICT_REAL) VERDICT_MAX( metric_vals->condition, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_JACOBIAN) { if( metric_vals->jacobian > 0 ) metric_vals->jacobian = (VERDICT_REAL) VERDICT_MIN( metric_vals->jacobian, VERDICT_DBL_MAX ); metric_vals->jacobian = (VERDICT_REAL) VERDICT_MAX( metric_vals->jacobian, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_SCALED_JACOBIAN) { if( metric_vals->scaled_jacobian > 0 ) metric_vals->scaled_jacobian = (VERDICT_REAL) VERDICT_MIN( metric_vals->scaled_jacobian, VERDICT_DBL_MAX ); metric_vals->scaled_jacobian = (VERDICT_REAL) VERDICT_MAX( metric_vals->scaled_jacobian, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_SHAPE) { if( metric_vals->shape > 0 ) metric_vals->shape = (VERDICT_REAL) VERDICT_MIN( metric_vals->shape, VERDICT_DBL_MAX ); metric_vals->shape = (VERDICT_REAL) VERDICT_MAX( metric_vals->shape, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_RELATIVE_SIZE_SQUARED) { if( metric_vals->relative_size_squared > 0 ) metric_vals->relative_size_squared = (VERDICT_REAL) VERDICT_MIN( metric_vals->relative_size_squared, VERDICT_DBL_MAX ); metric_vals->relative_size_squared = (VERDICT_REAL) VERDICT_MAX( metric_vals->relative_size_squared, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_SHAPE_AND_SIZE) { if( metric_vals->shape_and_size > 0 ) metric_vals->shape_and_size = (VERDICT_REAL) VERDICT_MIN( metric_vals->shape_and_size, VERDICT_DBL_MAX ); metric_vals->shape_and_size = (VERDICT_REAL) VERDICT_MAX( metric_vals->shape_and_size, -VERDICT_DBL_MAX ); } if(metrics_request_flag & V_TET_DISTORTION) { if( metric_vals->distortion > 0 ) metric_vals->distortion = (VERDICT_REAL) VERDICT_MIN( metric_vals->distortion, VERDICT_DBL_MAX ); metric_vals->distortion = (VERDICT_REAL) VERDICT_MAX( metric_vals->distortion, -VERDICT_DBL_MAX ); } }
/*! tri_quality for calculating multiple tri functions at once using this method is generally faster than using the individual method multiple times. */ C_FUNC_DEF void v_tri_quality( int num_nodes, double coordinates[][3], unsigned int metrics_request_flag, TriMetricVals *metric_vals ) { memset( metric_vals, 0, sizeof(TriMetricVals) ); // for starts, lets set up some basic and common information /* node numbers and side numbers used below 2 ++ / \ 2 / \ 1 / \ / \ 0 ---------+ 1 0 */ // vectors for each side VerdictVector sides[3]; sides[0].set( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); sides[1].set( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2] ); sides[2].set( coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1], coordinates[2][2] - coordinates[0][2] ); VerdictVector tri_normal = sides[0] * sides[2]; //if we have access to normal information, check to see if the //element is inverted. If we don't have the normal information //that we need for this, assume the element is not inverted. //This flag will be used for condition number, jacobian, shape, //and size and shape. bool is_inverted = false; if( compute_normal ) { //center of tri double point[3], surf_normal[3]; point[0] = (coordinates[0][0] + coordinates[1][0] + coordinates[2][0]) / 3; point[1] = (coordinates[0][1] + coordinates[1][1] + coordinates[2][1]) / 3; point[2] = (coordinates[0][2] + coordinates[1][2] + coordinates[2][2]) / 3; //dot product compute_normal( point, surf_normal ); if( (tri_normal.x()*surf_normal[0] + tri_normal.y()*surf_normal[1] + tri_normal.z()*surf_normal[2] ) < 0 ) is_inverted=true; } // lengths squared of each side double sides_lengths_squared[3]; sides_lengths_squared[0] = sides[0].length_squared(); sides_lengths_squared[1] = sides[1].length_squared(); sides_lengths_squared[2] = sides[2].length_squared(); // if we are doing angle calcuations if( metrics_request_flag & (V_TRI_MINIMUM_ANGLE | V_TRI_MAXIMUM_ANGLE) ) { // which is short and long side int short_side=0, long_side=0; if(sides_lengths_squared[1] < sides_lengths_squared[0]) short_side = 1; if(sides_lengths_squared[2] < sides_lengths_squared[short_side]) short_side = 2; if(sides_lengths_squared[1] > sides_lengths_squared[0]) long_side = 1; if(sides_lengths_squared[2] > sides_lengths_squared[long_side]) long_side = 2; // calculate the minimum angle of the tri if( metrics_request_flag & V_TRI_MINIMUM_ANGLE ) { if(sides_lengths_squared[0] == 0.0 || sides_lengths_squared[1] == 0.0 || sides_lengths_squared[2] == 0.0) { metric_vals->minimum_angle = 0.0; } else if(short_side == 0) metric_vals->minimum_angle = (double)sides[2].interior_angle(sides[1]); else if(short_side == 1) metric_vals->minimum_angle = (double)sides[0].interior_angle(sides[2]); else metric_vals->minimum_angle = (double)sides[0].interior_angle(-sides[1]); } // calculate the maximum angle of the tri if( metrics_request_flag & V_TRI_MAXIMUM_ANGLE ) { if(sides_lengths_squared[0] == 0.0 || sides_lengths_squared[1] == 0.0 || sides_lengths_squared[2] == 0.0) { metric_vals->maximum_angle = 0.0; } else if(long_side == 0) metric_vals->maximum_angle = (double)sides[2].interior_angle(sides[1]); else if(long_side == 1) metric_vals->maximum_angle = (double)sides[0].interior_angle(sides[2]); else metric_vals->maximum_angle = (double)sides[0].interior_angle(-sides[1]); } } // calculate the area of the tri // the following functions depend on area if( metrics_request_flag & (V_TRI_AREA | V_TRI_SCALED_JACOBIAN | V_TRI_SHAPE | V_TRI_RELATIVE_SIZE_SQUARED | V_TRI_SHAPE_AND_SIZE ) ) { metric_vals->area = (double)((sides[0] * sides[2]).length() * 0.5); } // calculate the aspect ratio if(metrics_request_flag & V_TRI_ASPECT_FROBENIUS) { // sum the lengths squared double srms = sides_lengths_squared[0] + sides_lengths_squared[1] + sides_lengths_squared[2] ; // calculate once and reuse static const double twoTimesRootOf3 = 2*sqrt(3.0); double div = (twoTimesRootOf3 * ( (sides[0] * sides[2]).length() )); if(div == 0.0) metric_vals->aspect_frobenius = (double)VERDICT_DBL_MAX; else metric_vals->aspect_frobenius = (double)(srms / div); } // calculate the radius ratio of the triangle if( metrics_request_flag & V_TRI_RADIUS_RATIO ) { double a1 = sqrt( sides_lengths_squared[0] ); double b1 = sqrt( sides_lengths_squared[1] ); double c1 = sqrt( sides_lengths_squared[2] ); VerdictVector ab = sides[0] * sides[1]; metric_vals->radius_ratio = (double) .25 * a1 * b1 * c1 * ( a1 + b1 + c1 ) / ab.length_squared(); } // calculate the scaled jacobian if(metrics_request_flag & V_TRI_SCALED_JACOBIAN) { // calculate once and reuse static const double twoOverRootOf3 = 2/sqrt(3.0); // use the area from above double tmp = tri_normal.length() * twoOverRootOf3; // now scale it by the lengths of the sides double min_scaled_jac = VERDICT_DBL_MAX; double temp_scaled_jac; for(int i=0; i<3; i++) { if(sides_lengths_squared[i%3] == 0.0 || sides_lengths_squared[(i+2)%3] == 0.0) temp_scaled_jac = 0.0; else temp_scaled_jac = tmp / sqrt(sides_lengths_squared[i%3]) / sqrt(sides_lengths_squared[(i+2)%3]); if( temp_scaled_jac < min_scaled_jac ) min_scaled_jac = temp_scaled_jac; } //multiply by -1 if the normals are in opposite directions if( is_inverted ) { min_scaled_jac *= -1; } metric_vals->scaled_jacobian = (double)min_scaled_jac; } // calculate the condition number if(metrics_request_flag & V_TRI_CONDITION) { // calculate once and reuse static const double rootOf3 = sqrt(3.0); //if it is inverted, the condition number is considered to be infinity. if(is_inverted){ metric_vals->condition = VERDICT_DBL_MAX; } else{ double area2x = (sides[0] * sides[2]).length(); if(area2x == 0.0 ) metric_vals->condition = (double)(VERDICT_DBL_MAX); else metric_vals->condition = (double) ( (sides[0]%sides[0] + sides[2]%sides[2] - sides[0]%sides[2]) / (area2x*rootOf3) ); } } // calculate the shape if(metrics_request_flag & V_TRI_SHAPE || metrics_request_flag & V_TRI_SHAPE_AND_SIZE) { //if element is inverted, shape is zero. We don't need to //calculate anything. if(is_inverted ){ metric_vals->shape = 0.0; } else{//otherwise, we calculate the shape // calculate once and reuse static const double rootOf3 = sqrt(3.0); // reuse area from before double area2x = metric_vals->area * 2; // dot products double dots[3] = { sides[0] % sides[0], sides[2] % sides[2], sides[0] % sides[2] }; // add the dots double sum_dots = dots[0] + dots[1] - dots[2]; // then the finale if( sum_dots == 0.0 ) metric_vals->shape = 0.0; else metric_vals->shape = (double)(rootOf3 * area2x / sum_dots); } } // calculate relative size squared if(metrics_request_flag & V_TRI_RELATIVE_SIZE_SQUARED || metrics_request_flag & V_TRI_SHAPE_AND_SIZE) { // get weights double w11, w21, w12, w22; v_tri_get_weight(w11,w21,w12,w22); // get the determinant double detw = v_determinant(w11,w21,w12,w22); // use the area from above and divide with the determinant if( metric_vals->area == 0.0 || detw == 0.0 ) metric_vals->relative_size_squared = 0.0; else { double size = metric_vals->area * 2.0 / detw; // square the size size *= size; // value ranges between 0 to 1 metric_vals->relative_size_squared = (double)VERDICT_MIN(size, 1.0/size ); } } // calculate shape and size if(metrics_request_flag & V_TRI_SHAPE_AND_SIZE) { metric_vals->shape_and_size = metric_vals->relative_size_squared * metric_vals->shape; } // calculate distortion if(metrics_request_flag & V_TRI_DISTORTION) metric_vals->distortion = v_tri_distortion(num_nodes, coordinates); //take care of any over-flow problems if( metric_vals->aspect_frobenius > 0 ) metric_vals->aspect_frobenius = (double) VERDICT_MIN( metric_vals->aspect_frobenius, VERDICT_DBL_MAX );\ else metric_vals->aspect_frobenius = (double) VERDICT_MAX( metric_vals->aspect_frobenius, -VERDICT_DBL_MAX ); if( metric_vals->area > 0 ) metric_vals->area = (double) VERDICT_MIN( metric_vals->area, VERDICT_DBL_MAX ); else metric_vals->area = (double) VERDICT_MAX( metric_vals->area, -VERDICT_DBL_MAX ); if( metric_vals->minimum_angle > 0 ) metric_vals->minimum_angle = (double) VERDICT_MIN( metric_vals->minimum_angle, VERDICT_DBL_MAX ); else metric_vals->minimum_angle = (double) VERDICT_MAX( metric_vals->minimum_angle, -VERDICT_DBL_MAX ); if( metric_vals->maximum_angle > 0 ) metric_vals->maximum_angle = (double) VERDICT_MIN( metric_vals->maximum_angle, VERDICT_DBL_MAX ); else metric_vals->maximum_angle = (double) VERDICT_MAX( metric_vals->maximum_angle , -VERDICT_DBL_MAX ); if( metric_vals->condition > 0 ) metric_vals->condition = (double) VERDICT_MIN( metric_vals->condition, VERDICT_DBL_MAX ); else metric_vals->condition = (double) VERDICT_MAX( metric_vals->condition, -VERDICT_DBL_MAX ); if( metric_vals->shape > 0 ) metric_vals->shape = (double) VERDICT_MIN( metric_vals->shape, VERDICT_DBL_MAX ); else metric_vals->shape = (double) VERDICT_MAX( metric_vals->shape, -VERDICT_DBL_MAX ); if( metric_vals->radius_ratio > 0 ) metric_vals->radius_ratio = (double) VERDICT_MIN( metric_vals->radius_ratio, VERDICT_DBL_MAX );\ else metric_vals->radius_ratio = (double) VERDICT_MAX( metric_vals->radius_ratio, -VERDICT_DBL_MAX ); if( metric_vals->scaled_jacobian > 0 ) metric_vals->scaled_jacobian = (double) VERDICT_MIN( metric_vals->scaled_jacobian, VERDICT_DBL_MAX ); else metric_vals->scaled_jacobian = (double) VERDICT_MAX( metric_vals->scaled_jacobian, -VERDICT_DBL_MAX ); if( metric_vals->relative_size_squared > 0 ) metric_vals->relative_size_squared = (double) VERDICT_MIN( metric_vals->relative_size_squared, VERDICT_DBL_MAX ); else metric_vals->relative_size_squared = (double) VERDICT_MAX( metric_vals->relative_size_squared, -VERDICT_DBL_MAX ); if( metric_vals->shape_and_size > 0 ) metric_vals->shape_and_size = (double) VERDICT_MIN( metric_vals->shape_and_size, VERDICT_DBL_MAX ); else metric_vals->shape_and_size = (double) VERDICT_MAX( metric_vals->shape_and_size, -VERDICT_DBL_MAX ); if( metric_vals->distortion > 0 ) metric_vals->distortion = (double) VERDICT_MIN( metric_vals->distortion, VERDICT_DBL_MAX ); else metric_vals->distortion = (double) VERDICT_MAX( metric_vals->distortion, -VERDICT_DBL_MAX ); }
/*! The distortion of a tri TODO: make a short definition of the distortion and comment below */ C_FUNC_DEF double v_tri_distortion( int num_nodes, double coordinates[][3] ) { double distortion; int total_number_of_gauss_points=0; VerdictVector aa, bb, cc,normal_at_point, xin; double element_area = 0.; aa.set(coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); bb.set(coordinates[2][0] - coordinates[0][0], coordinates[2][1] - coordinates[0][1], coordinates[2][2] - coordinates[0][2] ); VerdictVector tri_normal = aa * bb; int number_of_gauss_points=0; if (num_nodes ==3) { distortion = 1.0; return (double)distortion; } else if (num_nodes ==6) { total_number_of_gauss_points = 6; number_of_gauss_points = 6; } distortion = VERDICT_DBL_MAX; double shape_function[maxTotalNumberGaussPoints][maxNumberNodes]; double dndy1[maxTotalNumberGaussPoints][maxNumberNodes]; double dndy2[maxTotalNumberGaussPoints][maxNumberNodes]; double weight[maxTotalNumberGaussPoints]; //create an object of GaussIntegration int number_dims = 2; int is_tri = 1; GaussIntegration::initialize(number_of_gauss_points,num_nodes, number_dims, is_tri); GaussIntegration::calculate_shape_function_2d_tri(); GaussIntegration::get_shape_func(shape_function[0], dndy1[0], dndy2[0], weight); // calculate element area int ife, ja; for (ife=0;ife<total_number_of_gauss_points; ife++) { aa.set(0.0,0.0,0.0); bb.set(0.0,0.0,0.0); for (ja=0;ja<num_nodes;ja++) { xin.set(coordinates[ja][0], coordinates[ja][1], coordinates[ja][2]); aa += dndy1[ife][ja]*xin; bb += dndy2[ife][ja]*xin; } normal_at_point = aa*bb; double jacobian = normal_at_point.length(); element_area += weight[ife]*jacobian; } element_area *= 0.8660254; double dndy1_at_node[maxNumberNodes][maxNumberNodes]; double dndy2_at_node[maxNumberNodes][maxNumberNodes]; GaussIntegration::calculate_derivative_at_nodes_2d_tri( dndy1_at_node, dndy2_at_node); VerdictVector normal_at_nodes[7]; //evaluate normal at nodes and distortion values at nodes int jai=0; for (ja =0; ja<num_nodes; ja++) { aa.set(0.0,0.0,0.0); bb.set(0.0,0.0,0.0); for (jai =0; jai<num_nodes; jai++) { xin.set(coordinates[jai][0], coordinates[jai][1], coordinates[jai][2]); aa += dndy1_at_node[ja][jai]*xin; bb += dndy2_at_node[ja][jai]*xin; } normal_at_nodes[ja] = aa*bb; normal_at_nodes[ja].normalize(); } //determine if element is flat bool flat_element =true; double dot_product; for ( ja=0; ja<num_nodes;ja++) { dot_product = normal_at_nodes[0]%normal_at_nodes[ja]; if (fabs(dot_product) <0.99) { flat_element = false; break; } } // take into consideration of the thickness of the element double thickness, thickness_gauss; double distrt; //get_tri_thickness(tri, element_area, thickness ); thickness = 0.001*sqrt(element_area); //set thickness gauss point location double zl = 0.5773502691896; if (flat_element) zl =0.0; int no_gauss_pts_z = (flat_element)? 1 : 2; double thickness_z; //loop on integration points int igz; for (ife=0;ife<total_number_of_gauss_points;ife++) { //loop on the thickness direction gauss points for (igz=0;igz<no_gauss_pts_z;igz++) { zl = -zl; thickness_z = zl*thickness/2.0; aa.set(0.0,0.0,0.0); bb.set(0.0,0.0,0.0); cc.set(0.0,0.0,0.0); for (ja=0;ja<num_nodes;ja++) { xin.set(coordinates[jai][0], coordinates[jai][1], coordinates[jai][2]); xin += thickness_z*normal_at_nodes[ja]; aa += dndy1[ife][ja]*xin; bb += dndy2[ife][ja]*xin; thickness_gauss = shape_function[ife][ja]*thickness/2.0; cc += thickness_gauss*normal_at_nodes[ja]; } normal_at_point = aa*bb; distrt = cc%normal_at_point; if (distrt < distortion) distortion = distrt; } } //loop through nodal points for ( ja =0; ja<num_nodes; ja++) { for ( igz=0;igz<no_gauss_pts_z;igz++) { zl = -zl; thickness_z = zl*thickness/2.0; aa.set(0.0,0.0,0.0); bb.set(0.0,0.0,0.0); cc.set(0.0,0.0,0.0); for ( jai =0; jai<num_nodes; jai++) { xin.set(coordinates[jai][0], coordinates[jai][1], coordinates[jai][2]); xin += thickness_z*normal_at_nodes[ja]; aa += dndy1_at_node[ja][jai]*xin; bb += dndy2_at_node[ja][jai]*xin; if (jai == ja) thickness_gauss = thickness/2.0; else thickness_gauss = 0.; cc += thickness_gauss*normal_at_nodes[jai]; } } normal_at_point = aa*bb; double sign_jacobian = (tri_normal % normal_at_point) > 0? 1.:-1.; distrt = sign_jacobian * (cc%normal_at_point); if (distrt < distortion) distortion = distrt; } if (element_area*thickness !=0) distortion *=1./( element_area*thickness); else distortion *=1.; if( distortion > 0 ) return (double) VERDICT_MIN( distortion, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( distortion, -VERDICT_DBL_MAX ); }
/*! the edge ratio of a triangle NB (P. Pebay 01/14/07): Hmax / Hmin where Hmax and Hmin are respectively the maximum and the minimum edge lengths */ C_FUNC_DEF double v_tri_edge_ratio( int /*num_nodes*/, double coordinates[][3] ) { // three vectors for each side VerdictVector a( coordinates[1][0] - coordinates[0][0], coordinates[1][1] - coordinates[0][1], coordinates[1][2] - coordinates[0][2] ); VerdictVector b( coordinates[2][0] - coordinates[1][0], coordinates[2][1] - coordinates[1][1], coordinates[2][2] - coordinates[1][2] ); VerdictVector c( coordinates[0][0] - coordinates[2][0], coordinates[0][1] - coordinates[2][1], coordinates[0][2] - coordinates[2][2] ); double a2 = a.length_squared(); double b2 = b.length_squared(); double c2 = c.length_squared(); double m2, M2; if ( a2 < b2 ) { if ( b2 < c2 ) { m2 = a2; M2 = c2; } else // b2 <= a2 { if ( a2 < c2 ) { m2 = a2; M2 = b2; } else // c2 <= a2 { m2 = c2; M2 = b2; } } } else // b2 <= a2 { if ( a2 < c2 ) { m2 = b2; M2 = c2; } else // c2 <= a2 { if ( b2 < c2 ) { m2 = b2; M2 = a2; } else // c2 <= b2 { m2 = c2; M2 = a2; } } } if( m2 < VERDICT_DBL_MIN ) return (double)VERDICT_DBL_MAX; else { double edge_ratio; edge_ratio = sqrt(M2 / m2); if( edge_ratio > 0 ) return (double) VERDICT_MIN( edge_ratio, VERDICT_DBL_MAX ); return (double) VERDICT_MAX( edge_ratio, -VERDICT_DBL_MAX ); } }