If I know the vector components of the principal coordinate axes, how should I go about creating a coordinate system using Mechanical scripting?
Below is a code snippet to achieve this: `
import math ########################################################## # Created by P. Thieffry # Last update: 2021/04/07 def dotProduct(v1,v2): return v2[0]*v1[0]+v2[1]*v1[1]+v2[2]*v1[2] def TransformationMatrix(origCS,targCS): # compute transformation matrix to align origCS to targCS # All coordinates are expressed in the global CS # tMat=[[dotProduct(origCS[0],targCS[0]),dotProduct(origCS[0],targCS[1]),dotProduct(origCS[0],targCS[2])], [dotProduct(origCS[1],targCS[0]),dotProduct(origCS[1],targCS[1]),dotProduct(origCS[1],targCS[2])], [dotProduct(origCS[2],targCS[0]),dotProduct(origCS[2],targCS[1]),dotProduct(origCS[2],targCS[2])]] return tMat ########################################################## ########################################################## # Modified from: https://learnopencv.com/rotation-matrix-to-euler-angles/ def rotationMatrixToEulerAngles_ZYX( R ) : sy = math.sqrt(R[0][0] * R[0][0] + R[1][0] * R[1][0]) singular = sy < 1e-6 factor = 180./math.pi if not singular : x = math.atan2(R[2][1] , R[2][2])*factor y = math.atan2(-R[2][0], sy)*factor z = math.atan2(R[1][0], R[0][0])*factor else : x = math.atan2(-R[1][2], R[1][1])*factor y = math.atan2(-R[2][0], sy)*factor z = 0 return [z, y, x] ########################################################## def norm( v ): return ( v[0]**2 + v[1]**2 + v[2]**2 )**0.5 def unit_vec( v ): n = norm( v ) return [ _/n for _ in v ] def CreateCS( origin , xyz , name , unit='mm' ): # Create coordinate testCS = ExtAPI.DataModel.Project.Model.CoordinateSystems.AddCoordinateSystem() testCS.OriginDefineBy= CoordinateSystemAlignmentType.Fixed testCS.OriginX = Quantity(origin[0],unit) testCS.OriginY = Quantity(origin[1],unit) testCS.OriginZ = Quantity(origin[2],unit) # Get rotations origCS = [[1,0,0],[0,1,0],[0,0,1]] tMat = TransformationMatrix(origCS,xyz) angs = rotationMatrixToEulerAngles_ZYX(tMat) ########################################################## # Created by M.H. Pernelle # Last update: 2021/06 # Perform transformation testCS.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalX # Rotation Z testCS.RotateZ() testCS.SetTransformationValue(1,angs[0]) # Rotation Y testCS.RotateY() testCS.SetTransformationValue(2,angs[1]) # Rotation X testCS.RotateX() testCS.SetTransformationValue(3,angs[2]) ########################################################## # Set name testCS.Name = name # Example xyz = [[0.5,0.5,-0.70711],[-0.14645,0.85355,0.5],[0.85355,-0.14645,0.5]] CreateCS( [1,2,3] , xyz , 'my_cs' , unit='m' )
`
@Jimmy He , If you have any time/desire I am hoping to expand this solution to have a function that creates a CS with inputs of XYZ origin and a Z vector definition. X and Y can be arbitrary, but the Z direction should be from a unit vector.
Thanks for any help with this.
Hi @Mike.Thompson
Please see the updated solution here. The user can specify the unit of the origin XYZ. Angle unit is detected in the code and appropriate conversion is performed.
import math ########################################################## # Created by P. Thieffry # Last update: 2021/04/07 def dotProduct(v1,v2): return v2[0]*v1[0]+v2[1]*v1[1]+v2[2]*v1[2] def TransformationMatrix(origCS,targCS): # compute transformation matrix to align origCS to targCS # All coordinates are expressed in the global CS # tMat=[[dotProduct(origCS[0],targCS[0]),dotProduct(origCS[0],targCS[1]),dotProduct(origCS[0],targCS[2])], [dotProduct(origCS[1],targCS[0]),dotProduct(origCS[1],targCS[1]),dotProduct(origCS[1],targCS[2])], [dotProduct(origCS[2],targCS[0]),dotProduct(origCS[2],targCS[1]),dotProduct(origCS[2],targCS[2])]] return tMat ########################################################## ########################################################## # Modified from: https://learnopencv.com/rotation-matrix-to-euler-angles/ def rotationMatrixToEulerAngles_ZYX( R ) : sy = math.sqrt(R[0][0] * R[0][0] + R[1][0] * R[1][0]) singular = sy < 1e-6 if not singular : x = math.atan2(R[2][1] , R[2][2]) y = math.atan2(-R[2][0], sy) z = math.atan2(R[1][0], R[0][0]) else : x = math.atan2(-R[1][2], R[1][1]) y = math.atan2(-R[2][0], sy) z = 0 return [z, y, x] ########################################################## def norm( v ): return ( v[0]**2 + v[1]**2 + v[2]**2 )**0.5 def unit_vec( v ): n = norm( v ) return [ _/n for _ in v ] def cross(a, b): result = [a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0]] return result def CreateCS( origin , z , name , unit='mm' ): angle_unit = DataModel.CurrentUnitFromQuantityName("Angle") convert_factor = Quantity(1,'rad').ConvertUnit( angle_unit ).Value # Create coordinate testCS = ExtAPI.DataModel.Project.Model.CoordinateSystems.AddCoordinateSystem() testCS.OriginDefineBy= CoordinateSystemAlignmentType.Fixed testCS.OriginX = Quantity(origin[0],unit) testCS.OriginY = Quantity(origin[1],unit) testCS.OriginZ = Quantity(origin[2],unit) z_unit = unit_vec(z) x_unit = unit_vec([ z_unit[1] , -z_unit[0] , 0 ]) y_unit = unit_vec(cross(z_unit, x_unit)) xyz = [ x_unit , y_unit , z_unit ] # Get rotations origCS = [[1,0,0],[0,1,0],[0,0,1]] tMat = TransformationMatrix(origCS,xyz) angs = rotationMatrixToEulerAngles_ZYX(tMat) ########################################################## # Created by M.H. Pernelle # Last update: 2021/06 # Perform transformation testCS.PrimaryAxisDefineBy = CoordinateSystemAlignmentType.GlobalX # Rotation Z testCS.RotateZ() testCS.SetTransformationValue(1,angs[0]*convert_factor) # Rotation Y testCS.RotateY() testCS.SetTransformationValue(2,angs[1]*convert_factor) # Rotation X testCS.RotateX() testCS.SetTransformationValue(3,angs[2]*convert_factor) ########################################################## # Set name testCS.Name = name # Example z = [1.,1.,0.] CreateCS( [0,0,0] , z , 'my_cs' , unit='m' )