Get Component Rotation (x, y, z)

I need to copy into clipboard, selected component’s position and rotation values.
For position coordinates, I use transformation.origin.
But i cant find information, how to get component rotation values.

instance.transformation.xaxis.angle_between(X_AXIS) will give you the x rotation angle in radians

The Transformation class supports “rotx”, “roty”, and “rotz” methods. Those methods return the angles in degrees, not radians. I believe those methods are only available when the “Dynamic Components” extension is enabled (which it is by default).

1 Like

Mathematically decomposing a transformation matrix does not give a single solution (e.g. +170° and -190°). If you have bad luck, the component is skewed/sheared and you get nonesense. Under the premise that there is no shear, it is possible.

# Separate translation, scaling and rotation components of a 4×4
# augmented rotation matrix without shear.
# 
# @param m [Array(16)] matrix
# @returns three arrays of three floats
def separate_translation_scaling_rotation(m)
  m = m.clone
  # Extract translation
  translation = m.values_at(12, 13, 14)
  # Extract scaling, considering uniform scale factor (last matrix element)
  scaling = Array.new(3)
  scaling[0] = m[15] * Math.sqrt(m[0]**2 + m[1]**2 + m[2]**2)
  scaling[1] = m[15] * Math.sqrt(m[4]**2 + m[5]**2 + m[6]**2)
  scaling[2] = m[15] * Math.sqrt(m[8]**2 + m[9]**2 + m[10]**2)
  # Remove scaling to prepare for extraction of rotation
  [0,1,2].each{ |i| m[i] /= scaling[0] }  unless scaling[0] == 0.0
  [4,5,6].each{ |i| m[i] /= scaling[1] }  unless scaling[1] == 0.0
  [8,9,10].each{ |i| m[i] /= scaling[2] } unless scaling[2] == 0.0
  m[15]  = 1.0
  # Verify orientation
  tmp_z_axis = Geom::Vector3d.new(m[0], m[1], m[2]).cross(Geom::Vector3d.new(m[4], m[5], m[6]))
  if tmp_z_axis.dot( Geom::Vector3d.new(m[8], m[9], m[10]) ) < 0
    scaling[0] *= -1
    m[0] = -m[0]
    m[1] = -m[1]
    m[2] = -m[2]
  end
  # Extract rotation
  # Source: Extracting Euler Angles from a Rotation Matrix, Mike Day, Insomniac Games
  # http://www.insomniacgames.com/mike-day-extracting-euler-angles-from-a-rotation-matrix/
  theta1 = Math.atan2(m[6], m[10])
  c2 = Math.sqrt(m[0]**2 + m[1]**2)
  theta2 = Math.atan2(-m[2], c2)
  s1 = Math.sin(theta1)
  c1 = Math.cos(theta1)
  theta3 = Math.atan2(s1*m[8] - c1*m[4], c1*m[5] - s1*m[9])
  rotation = [-theta1, -theta2, -theta3]
  
  return translation, scaling, rotation
end

The dynamic components extension extends core ruby classes which is not recommended. Since SketchUp has no dependency resolving package manager, your users will report to you errors when they have not installed and activated dynamic components. Better have the code in your own extension.

4 Likes

I hope Bruce’s answer helps, otherwise you could decompose the transformation matrix.

I believe that the translations and rotations of a component are all combined into the transformation matrix, so if you want to get the original rotation values back, you are looking at some really nasty maths.

You can get the 16 elements of the 4x4 transformation matrix with the to_a method.
Then you need to look at the really scary stuff:

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.