def from_matrix(cls, matrix): """Construct a frame from a matrix. Parameters ---------- matrix : :obj:`list` of :obj:`list` of :obj:`float` The 4x4 transformation matrix in row-major order. Returns ------- Frame The constructed frame. Examples -------- >>> from compas.geometry import Frame >>> from compas.geometry import matrix_from_euler_angles >>> ea1 = [0.5, 0.4, 0.8] >>> M = matrix_from_euler_angles(ea1) >>> f = Frame.from_matrix(M) >>> ea2 = f.euler_angles() >>> allclose(ea1, ea2) True """ sc, sh, a, point, p = decompose_matrix(matrix) R = matrix_from_euler_angles(a, static=True, axes='xyz') xaxis, yaxis = basis_vectors_from_matrix(R) return cls(point, xaxis, yaxis)
def from_euler_angles(cls, euler_angles, static=True, axes='xyz', point=[0, 0, 0]): """Construct a transformation from a rotation represented by Euler angles. Parameters ---------- euler_angles : list of float Three numbers that represent the angles of rotations about the defined axes. static : bool, optional If true the rotations are applied to a static frame. If not, to a rotational. Defaults to ``True``. axes : str, optional A 3 character string specifying the order of the axes. Defaults to ``'xyz'``. point : list of float, optional The point of the frame. Defaults to ``[0, 0, 0]``. Returns ------- :class:`compas.geometry.Transformation` The constructed transformation. """ R = matrix_from_euler_angles(euler_angles, static, axes) T = matrix_from_translation(point) M = multiply_matrices(T, R) return cls.from_matrix(M)
def __init__(self, matrix=None): if matrix: _, _, angles, _, _ = decompose_matrix(matrix) check = matrix_from_euler_angles(angles) if not allclose(flatten(matrix), flatten(check)): raise ValueError('This is not a proper rotation matrix.') super(Rotation, self).__init__(matrix=matrix)
def basis_vectors(self): """Returns the basis vectors from the ``Rotation`` component of the ``Transformation``. """ sc, sh, a, t, p = decompose_matrix(self.matrix) R = matrix_from_euler_angles(a, static=True, axes='xyz') xv, yv = basis_vectors_from_matrix(R) return Vector(*xv), Vector(*yv)
def test_matrix_from_euler_angles(): ea1 = 1.4, 0.5, 2.3 args = True, 'xyz' R = matrix_from_euler_angles(ea1, *args) r = [[-0.5847122176808724, -0.4415273357486694, 0.6805624396639868, 0.0], [0.6544178905170501, 0.23906322244658262, 0.7173464994301357, 0.0], [-0.479425538604203, 0.8648134986574489, 0.14916020070358058, 0.0], [0.0, 0.0, 0.0, 1.0]] assert np.allclose(R, r)
def basis_vectors(self): """Returns the basis vectors from the ``Rotation`` component of the ``Transformation``. """ # this has to be here to avoid circular import from compas.geometry.primitives import Vector sc, sh, a, t, p = decompose_matrix(self.matrix) R = matrix_from_euler_angles(a, static=True, axes='xyz') xv, yv = basis_vectors_from_matrix(R) return Vector(*xv), Vector(*yv)
def from_euler_angles(cls, euler_angles, static=True, axes='xyz', point=[0, 0, 0]): """Construct a frame from a rotation represented by Euler angles. Parameters ---------- euler_angles : :obj:`list` of :obj:`float` Three numbers that represent the angles of rotations about the defined axes. static : :obj:`bool`, optional If true the rotations are applied to a static frame. If not, to a rotational. Defaults to true. axes : :obj:`str`, optional A 3 character string specifying the order of the axes. Defaults to 'xyz'. point : :obj:`list` of :obj:`float`, optional The point of the frame. Defaults to [0, 0, 0]. Returns ------- Frame The constructed frame. Examples -------- >>> from compas.geometry import Frame >>> ea1 = 1.4, 0.5, 2.3 >>> f = Frame.from_euler_angles(ea1, static = True, axes = 'xyz') >>> ea2 = f.euler_angles(static = True, axes = 'xyz') >>> allclose(ea1, ea2) True """ R = matrix_from_euler_angles(euler_angles, static, axes) xaxis, yaxis = basis_vectors_from_matrix(R) return cls(point, xaxis, yaxis)
def from_euler_angles(cls, euler_angles, static=True, axes='xyz'): """Calculates a ``Rotation`` from Euler angles. In 3D space any orientation can be achieved by composing three elemental rotations, rotations about the axes (x,y,z) of a coordinate system. A triple of Euler angles can be interpreted in 24 ways, which depends on if the rotations are applied to a static (extrinsic) or rotating (intrinsic) frame and the order of axes. Parameters ---------- euler_angles: list of float Three numbers that represent the angles of rotations about the defined axes. static: bool, optional If true the rotations are applied to a static frame. If not, to a rotational. Defaults to true. axes: str, optional A 3 character string specifying order of the axes. Defaults to 'xyz'. Examples -------- >>> ea1 = 1.4, 0.5, 2.3 >>> args = False, 'xyz' >>> R1 = Rotation.from_euler_angles(ea1, *args) >>> ea2 = R1.euler_angles(*args) >>> allclose(ea1, ea2) True >>> alpha, beta, gamma = ea1 >>> xaxis, yaxis, zaxis = [1, 0, 0], [0, 1, 0], [0, 0, 1] >>> Rx = Rotation.from_axis_and_angle(xaxis, alpha) >>> Ry = Rotation.from_axis_and_angle(yaxis, beta) >>> Rz = Rotation.from_axis_and_angle(zaxis, gamma) >>> R2 = Rx * Ry * Rz >>> R1 == R2 True """ R = cls() R.matrix = matrix_from_euler_angles(euler_angles, static, axes) return R
def test_euler_angles_from_matrix(): ea1 = 1.4, 0.5, 2.3 args = True, 'xyz' R = matrix_from_euler_angles(ea1, *args) ea2 = euler_angles_from_matrix(R, *args) assert np.allclose(ea1, ea2)
if __name__ == '__main__': f1 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) R = Rotation.from_frame(f1) f2 = Frame.from_rotation(R, point=f1.point) print(f1 == f2) print(f2) f1 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = Transformation.from_frame(f1) f2 = Frame.from_transformation(T) print(f1 == f2) ea1 = [0.5, 0.4, 0.8] M = matrix_from_euler_angles(ea1) f = Frame.from_matrix(M) ea2 = f.euler_angles() print(allclose(ea1, ea2)) q1 = [0.945, -0.021, -0.125, 0.303] f = Frame.from_quaternion(q1, point=[1., 1., 1.]) q2 = f.quaternion print(allclose(q1, q2, tol=1e-03)) aav1 = [-0.043, -0.254, 0.617] f = Frame.from_axis_angle_vector(aav1, point=[0, 0, 0]) aav2 = f.axis_angle_vector print(allclose(aav1, aav2)) ea1 = 1.4, 0.5, 2.3
f1 = Frame([2, 2, 2], [0.12, 0.58, 0.81], [-0.80, 0.53, -0.26]) f2 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = Transformation.from_frame_to_frame(f1, f2) f1.transform(T) print(f1 == f2) f = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = Transformation.from_frame(f) p = Point(0, 0, 0) p.transform(T) print(allclose(f.point, p)) f1 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15]) T = Transformation.from_frame(f1) points = [[1.0, 1.0, 1.0], [1.68, 1.68, 1.27], [0.33, 1.73, 0.85]] points = transform_points(points, T) trans1 = [1, 2, 3] angle1 = [-2.142, 1.141, -0.142] scale1 = [0.123, 2, 0.5] T = matrix_from_translation(trans1) R = matrix_from_euler_angles(angle1) S = matrix_from_scale_factors(scale1) M = multiply_matrices(multiply_matrices(T, R), S) # M = compose_matrix(scale1, None, angle1, trans1, None) scale2, shear2, angle2, trans2, persp2 = decompose_matrix(M) print(allclose(scale1, scale2)) print(allclose(angle1, angle2)) print(allclose(trans1, trans2))