/* Do transform M_hat = S_a M_{3x2}, M_{2x2} Theta^-1 M_hat * where the plane into which we are projecting is orthogonal * to the passed u vector. */ static inline bool project_to_perp_plane( MsqMatrix<3,2> J, const MsqVector<3>& u, const MsqVector<3>& u_perp, MsqMatrix<2,2>& A, MsqMatrix<3,2>& S_a_transpose_Theta ) { MsqVector<3> n_a = J.column(0) * J.column(1); double sc, len = length(n_a); if (!divide(1.0, len, sc)) return false; n_a *= sc; double ndot = n_a % u; double sigma = (ndot < 0.0) ? -1 : 1; double cosphi = sigma * ndot; MsqVector<3> cross = n_a * u; double sinphi = length(cross); MsqMatrix<3,2> Theta; Theta.set_column(0, u_perp); Theta.set_column(1, u*u_perp); // If columns of J are not in plane orthogonal to u, then // rotate J such that they are. if (sinphi > 1e-12) { MsqVector<3> m = sigma * cross; MsqVector<3> n = (1/sinphi) * m; MsqVector<3> p = (1-cosphi) * n; double s_a[] = { p[0]*n[0] + cosphi, p[0]*n[1] - m[2], p[0]*n[2] + m[1], p[1]*n[0] + m[2], p[1]*n[1] + cosphi, p[1]*n[2] - m[0], p[2]*n[0] - m[1], p[2]*n[1] + m[0], p[2]*n[2] + cosphi }; MsqMatrix<3,3> S_a(s_a); J = S_a * J; S_a_transpose_Theta = transpose(S_a) * Theta; } else { S_a_transpose_Theta = Theta; // J *= sigma; } // Project to get 2x2 A from A_hat (which might be equal to J) A = transpose(Theta) * J; return true; }
template <class QMType> inline void TMPQualityMetricTest<QMType>::test_evaluate_3D() { MsqPrintError err(cout); PatchData pd; bool rval; double value; QMType m( &ideal, &faux_two ); // test with aligned elements faux_two.count = 0; tester.get_ideal_element( HEXAHEDRON, true, pd ); rval = m.evaluate( pd, 0, value, err ); CPPUNIT_ASSERT(!MSQ_CHKERR(err)); CPPUNIT_ASSERT(rval); CPPUNIT_ASSERT_DOUBLES_EQUAL( faux_two.value, value, DBL_EPSILON ); CPPUNIT_ASSERT_EQUAL( 1, faux_two.count ); // test that columns are orthogonal for ideal hex element MsqMatrix<3,3> A = faux_two.last_A_3D; CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(0) % A.column(1), 1e-6 ); CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(0) % A.column(2), 1e-6 ); CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(1) % A.column(2), 1e-6 ); // test with rotated element faux_two.count = 0; tester.get_ideal_element( TETRAHEDRON, true, pd ); // rotate by 90-degrees about X axis for (size_t i = 0; i < pd.num_nodes(); ++i) { Vector3D orig = pd.vertex_by_index(i); Vector3D newp( orig[0], -orig[2], orig[1] ); pd.set_vertex_coordinates( newp, i, err ); } rval = m.evaluate( pd, 0, value, err ); CPPUNIT_ASSERT(!MSQ_CHKERR(err)); CPPUNIT_ASSERT(rval); CPPUNIT_ASSERT_DOUBLES_EQUAL( faux_two.value, value, DBL_EPSILON ); CPPUNIT_ASSERT_EQUAL( 1, faux_two.count ); }
void test_3d_eval_ortho_hex() { MsqPrintError err(cout); PatchData pd; bool rval; double value; QMType m( &ideal, &faux_zero ); faux_zero.count = 0; tester.get_ideal_element( HEXAHEDRON, true, pd ); rval = m.evaluate( pd, 0, value, err ); CPPUNIT_ASSERT(!MSQ_CHKERR(err)); CPPUNIT_ASSERT(rval); CPPUNIT_ASSERT_EQUAL( 1, faux_zero.count ); // test that columns are orthogonal for ideal hex element MsqMatrix<3,3> A = faux_zero.last_A_3D; CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(0) % A.column(1), 1e-6 ); CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(0) % A.column(2), 1e-6 ); CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.0, A.column(1) % A.column(2), 1e-6 ); }
bool LambdaTarget::get_surface_target( PatchData& pd, size_t element, Sample sample, MsqMatrix<3,2>& W_out, MsqError& err ) { bool valid = lambdaSource->get_surface_target( pd, element, sample, W_out, err ); if (MSQ_CHKERR(err) && !valid) return false; MsqVector<3> cross = W_out.column(0) * W_out.column(1); double det1 = cross % cross; // length squared valid = compositeSource->get_surface_target( pd, element, sample, W_out, err ); if (MSQ_CHKERR(err) && !valid) return false; cross = W_out.column(0) * W_out.column(1); double det2 = cross % cross; // length squared if (det2 < 1e-15) return false; W_out *= sqrt( sqrt( det1/det2 ) ); return true; }