Yehyun Suh

[수학 to 파이썬] 3D Coordinate Transformation (3차원 좌표 변환) 본문

파이썬/수학 to 파이썬

[수학 to 파이썬] 3D Coordinate Transformation (3차원 좌표 변환)

Yehyun Suh 2023. 11. 28. 01:51

3차원 좌표가 x축을 기준으로 θ1만큼, y축을 기준으로 θ2만큼, 그리고 z축을 기준으로 θ3만큼 돌아간다고 했을 때, 변환된 좌표의 값을 어떻게 구할까? (이 글에서는 translation과 scaling이 없다고 가정한다.)

1. 3차원 좌표 변환 공식

3차원 좌표를 각각 x축, y축, 그리고 z축으로 변환하는 행렬을 Rx(θ1), Ry(θ2), 그리고 Rz(θ3) 이라고 했을 때, 3차원 좌표를 움직이는 행렬 R

R=Rz(θ3)Ry(θ2)Rx(θ1) 

로 정의할 수 있다. 이때 각각의  Rx(θ), Ry(θ), 그리고 Rz(θ)

Rx(θ)=[10000cosθsinθ00sinθcosθ00001] 

Ry(θ)=[cosθ0sinθ00100sinθ0cosθ00001] 

Rz(θ)=[cosθsinθ00sinθcosθ0000100001] 

이기 때문에, 이를 이용하여 행렬 R을 구하면

R=Rz(θ3)Ry(θ2)Rx(θ1)=[10000cosθ3sinθ300sinθ3cosθ300001][cosθ20sinθ200100sinθ20cosθ200001][cosθ1sinθ100sinθ1cosθ10000100001]

이 된다. 그렇다면 우리가 좌표 (x,y,z)를 변환시켜준다고 하면, 변환된 좌표 (x,y,z)

[xyz1]=[10000cosθ3sinθ300sinθ3cosθ300001][cosθ20sinθ200100sinθ20cosθ200001][cosθ1sinθ100sinθ1cosθ10000100001][xyz1]

로 표현할 수 있다. 이제 이 식을 코드로 적어보자.

2. 코드

import numpy as np


def rotation_function(theta: np.array, coordinate: np.array) -> np.array:
    """
    3차원 좌표의 coordinate transformation을 해주는 함수
    :param theta: x축, y축, z축 변환 각도, 모든 값은 radian 값이어야 한다
    :param coordinate: 3차원 (x, y, z) 좌표, array의 shape은 (1, 3) 이어야 한다
    :return: coordinate transformation이 완료된 3차원 좌표
    """
    rotation_x = np.array([
        [1, 0, 0, 0],
        [0, np.cos(theta[0]), -np.sin(theta[0]), 0],
        [0, np.sin(theta[0]), np.cos(theta[0]), 0],
        [0, 0, 0, 1]
    ])
    rotation_y = np.array([
        [np.cos(theta[1]), 0, np.sin(theta[1]), 0],
        [0, 1, 0, 0],
        [-np.sin(theta[1]), 0, np.cos(theta[1]), 0],
        [0, 0, 0, 1]
    ])
    rotation_z = np.array([
        [np.cos(theta[2]), -np.sin(theta[2]), 0, 0],
        [np.sin(theta[2]), np.cos(theta[2]), 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]
    ])

    rotation_matrix = rotation_z @ rotation_y @ rotation_x
    transposed_coordinate = coordinate.T
    padded_coordinate = np.concatenate((transposed_coordinate, np.ones((1, transposed_coordinate.shape[1]))), axis=0)
    return (rotation_matrix @ padded_coordinate)[0:3, :].T

3. 예시

theta = np.array([30, 60, -45]) * np.pi/180
coordinate = np.array([[10, -20, 10]])
rotated_coordinate = rotation_function(theta, coordinate)
print(rotated_coordinate)
[[-13.06787221 -18.49809303  -9.33012702]]