3D空間における座標変換例
(1,1,1)の点をX軸まわりに30度回転するPythonプログラム
工学分野において,回転行列はよく用いられる.
Pythonパッケージ NumPy の配列 Arrayモジュールの使い方の例として,
サンプルプログラムを示す.
座標変換が分かりやすいように,元の位置と移動後の位置をアニメーションとして可視化するとともに,
gifファイルとして出力するようにした.
rot_matrix.py
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import imageio
def rotate_x(point, angle_deg):
"""
指定された点をx軸周りに回転させる変換行列を適用する関数
Args:
point (np.array): 回転させる点の座標 (x, y, z)
angle_deg (float): 回転角度(度数法)
Returns:
np.array: 回転後の点の座標
"""
angle_rad = np.radians(angle_deg)
# x軸周りの回転行列
# R_x = [[1, 0, 0],
# [0, cos(theta), -sin(theta)],
# [0, sin(theta), cos(theta)]]
rotation_matrix = np.array([
[1, 0, 0],
[0, np.cos(angle_rad), -np.sin(angle_rad)],
[0, np.sin(angle_rad), np.cos(angle_rad)]
])
# 点に変換行列を適用
rotated_point = np.dot(rotation_matrix, point)
return rotated_point
# 元の点
original_point = np.array([1, 1, 1])
# 回転角度
rotation_angle_deg = 30
# 回転後の点
rotated_point = rotate_x(original_point, rotation_angle_deg)
print(f"元の点: {original_point}")
print(f"X軸周りに{rotation_angle_deg}度回転後の点: {rotated_point}")
## GIFアニメーションの生成
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(111, projection='3d')
# 軸ラベルの設定
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
# 軸の範囲を設定 (点の移動範囲を考慮して少し広めに)
ax.set_xlim([-1.5, 1.5])
ax.set_ylim([-1.5, 1.5])
ax.set_zlim([-1.5, 1.5])
# プロットの初期化
# 元の点と回転後の点を表示
# ここで凡例に回転後の座標値を含める
ax.plot([original_point[0]], [original_point[1]], [original_point[2]], 'ro', markersize=8, label='Original Point (1,1,1)')
ax.plot(
[rotated_point[0]], [rotated_point[1]], [rotated_point[2]],
'bo', markersize=8, label=f'Rotated Point ({rotation_angle_deg} deg): ({rotated_point[0]:.2f}, {rotated_point[1]:.2f}, {rotated_point[2]:.2f})'
)
# 現在の点をプロットするハンドラ
point_handler, = ax.plot([], [], [], 'go', markersize=10, label='Moving Point')
# 凡例の表示
ax.legend()
# アニメーションのフレーム数 (1秒間で移動、例えば50フレーム)
num_frames = 50
interval_ms = 1000 / num_frames # 1秒 / フレーム数
def update(frame):
"""
アニメーションの各フレームを更新する関数
"""
# 線形補間により、元の点から回転後の点へ移動
# tは0から1まで変化
t = frame / (num_frames - 1)
current_point = original_point * (1 - t) + rotated_point * t
point_handler.set_data([current_point[0]], [current_point[1]])
point_handler.set_3d_properties([current_point[2]])
return point_handler,
# アニメーションの作成
ani = FuncAnimation(fig, update, frames=num_frames, blit=True, interval=interval_ms)
# GIFとして保存
gif_filename = "3d_rotation_animation.gif"
ani.save(gif_filename, writer='imageio', fps=num_frames / 1) # fpsは1秒あたりのフレーム数
print(f"アニメーションGIF '{gif_filename}' が生成されました。")
plt.show()