--- a +++ b/Tools/ModelUtilities/SegmentCoM/CreateCoMRefNode.any @@ -0,0 +1,93 @@ +/* +--- +group: Utilities +topic: Center of mass +descr: | + Class template to create a reference node at the center of mass of a segment + with its axis aligned with the principal axes of inertia. +--- + +To use the class template import the file: +#include "<ANYBODY_PATH_MODELUTILS>/SegmentCoM/CreateCoMRefNode.any" + +*/ + + +// Creates a reference node at the center of mass of the segment. The orientation of the reference +// node is determined from the principal axes of inertia, which are determined from the Jmatrix of +// the segment. This class template must be used inside the scope of AnySeg. +// +// This class template calculates the Jmatrix about the center of mass and its eigenvectors and eigenvalues +// to determine the principal axes of inertia. In cases with symmetric shape, for example a sphere, +// cylinder, etc., some of the eigenvalue terms are duplicated. Therefore, the principal axes may not +// be uniquely defined in these cases. +// +// In the example below a reference node is created inside a segment. +// +// :::{rubric} Example +// ::: +// +// :::{code-block} AnyScriptDoc +// AnySeg MySegment = { +// CreateCoMRefNode CoMNode () = { +// viewRefFrame.Visible = On; +// }; +// }; +//::: +// +#class_template CreateCoMRefNode (__CLASS__ = AnyRefNode, + SUPPRESS_SYMMETRY_NOTICE = "Off"){ + // Arguments + // ----------- + // CreateCoMRefNode#SUPPRESS_SYMMETRY_NOTICE + // Switch to suppress the notice detecting duplicate eigenvalues of the Jmatrix about the center of mass, + // indicating that two or three axes of the center of mass node may not be uniquely defined. + + /// Jmatrix about the center of mass + AnyMat33 JMatrixCoM = .Jmatrix + .Mass*skewmat3d(.sCoM)*skewmat3d(.sCoM); + /// Matrix with eigenvectors and eigenvalues from the Jmatrix about center of mass + AnyMatrix JMatrixEV = LAPACK_syevd(JMatrixCoM,"V","V"); + /// Eigenvectors of the Jmatrix about the center of mass + AnyFloat EigenVectors = {JMatrixEV[0],JMatrixEV[1],JMatrixEV[2]}; + /// Eigenvalues of the Jmatrix about the center of mass + AnyFloat EigenValues = JMatrixEV[3]; + + #if SUPPRESS_SYMMETRY_NOTICE == "Off" + /// Check if first and second eigenvalues are same + AnyInt test0_1 = iffun(ltfun(abs(EigenValues[0]-EigenValues[1]),SymmetryTolerance),1,0); + /// Check if second and third eigenvalues are same + AnyInt test1_2 = iffun(ltfun(abs(EigenValues[1]-EigenValues[2]),SymmetryTolerance),1,0); + /// Check if first and third eigenvalues are same + AnyInt test0_2 = iffun(ltfun(abs(EigenValues[0]-EigenValues[2]),SymmetryTolerance),1,0); + /// Sum of the three tests. + AnyInt sumcheck = test0_1+test1_2+test0_2; + /// Notice when 2 Eigenvalues are same + AnyInt AxisNotice_2 = notice(sumcheck-1, strformat("2 of 3 eigenvalues are the same. 2 axes of the Center of Mass node may not be uniquely defined due to symmetric moment of inertia about 2 axes.\n\t\t\tYou can suppress this notice by setting SUPPRESS_SYMMETRY_NOTICE = " + strquote("On"))); + /// Notice when 3 Eigenvalues are same + AnyInt AxisNotice_3 = notice(sumcheck-3, strformat("3 of 3 eigenvalues are the same. The axes of the Center of Mass node may not be uniquely defined due to symmetric moment of inertia about 3 axes. \n\t\t\tYou can suppress this notice by setting SUPPRESS_SYMMETRY_NOTICE = " + strquote("On"))); + #endif + + //CreateCoMRefNode + /// Tolerance for checking duplicate eigenvalues + #var AnyFloat SymmetryTolerance = 1e-10; + + // sRel + /// Relative position of the reference node in the segmental frame. This defaults to + /// segment sCoM. + #var sRel = .sCoM; + // ARel + /// Relative orientation of the reference node in the segmental frame. This defaults to + /// be aligned with the principal axes of inertia. + #var ARel = {EigenVectors[0],EigenVectors[1],cross(EigenVectors[0],EigenVectors[1])}'; + viewRefFrame = { + // viewRefFrame.Visible + /// Switch to view the reference node. + #var Visible = Off; + // viewRefFrame.ScaleXYZ + /// Size of the drawing of the reference node. + #var ScaleXYZ = 0.5*{1,1,1}; + // viewRefFrame.RGB + /// Color of the drawing of the reference node. + #var RGB = {0.8,0.2,0.2}; + }; +}; \ No newline at end of file