欧拉角与法向量之间的相互转换(附代码)
欧拉角与法向量之间的相互转换(附代码)
- 一、 欧拉角的定义
- 1. 基本概念
- 2. 旋转轴与顺序
- 3. 万向锁(Gimbal Lock)
- 二、 欧拉角与旋转矩阵的转换(XYZ顺序)
- 1. 欧拉角 → 旋转矩阵(外旋)
- 2. 旋转矩阵 → 欧拉角(XYZ顺序)
- 三、法向量转欧拉角(XYZ顺序)
- 四、欧拉角转法向量(XYZ顺序)
- 五、代码实现(python)
一、 欧拉角的定义
1. 基本概念
欧拉角是描述三维空间中物体姿态的三个角度参数,通过绕三个正交坐标轴的连续旋转来唯一确定物体的方向。其核心思想是 将复杂的三维旋转分解为三个独立的单轴旋转。顺序不同会导致不同的结果。
典型应用:机器人运动学、飞行器导航、三维图形渲染。
2. 旋转轴与顺序
常见旋转顺序:
- ZYX(偏航Yaw→俯仰Pitch→横滚Roll):常用于无人机、机器人。
- XYZ:常见于计算机图形学。
- ZYZ:用于机械臂和分子动力学。
内旋(Intrinsic)与外旋(Extrinsic):
- 内旋:绕物体自身旋转后的坐标系旋转。
- 外旋:绕固定世界坐标系旋转。
3. 万向锁(Gimbal Lock)
- 问题:当中间旋转角为±90°时,第一轴和第三轴对齐,丢失一个自由度。
- 解决方法:使用四元数或旋转矩阵替代欧拉角。
二、 欧拉角与旋转矩阵的转换(XYZ顺序)
1. 欧拉角 → 旋转矩阵(外旋)
最终旋转矩阵(外旋):
R=Rx⋅Ry ⋅Rz
2. 旋转矩阵 → 欧拉角(XYZ顺序)
设旋转矩阵元素为 R ij,计算步骤:
三、法向量转欧拉角(XYZ顺序)
法向量(如物体表面朝向)可视为旋转后的Z轴方向。通过构建正交坐标系并分解出XYZ欧拉角。
具体步骤:
1.归一化法向量:
2.构建正交坐标系:
-
新Z轴:法向量
-
临时参考轴(如Y轴):若法向量与原Y轴重合,改用X轴。
-
计算新X轴:
-
计算新Y轴:
3.构造旋转矩阵:
4.分解欧拉角: 使用旋转矩阵→欧拉角的方法(XYZ顺序)
四、欧拉角转法向量(XYZ顺序)
通过欧拉角生成旋转矩阵,提取旋转后的Z轴方向即为法向量。
具体步骤:
- 生成旋转矩阵:按XYZ顺序计算外旋矩阵。 R=Rx (α)⋅Ry (β)⋅Rz (γ)(α,β,γ为对应欧拉角)
- 提取法向量:旋转矩阵的第三列即为旋转后的Z轴方向。
五、代码实现(python)
代码功能:输出平面法向量,可输出 1、对应单位法向量,2、由该单位法向量求出的欧拉角(XYZ顺序),3、由求出的欧拉角重新求其单位法向量
import numpy as np
from scipy.spatial.transform import Rotation
def normal_to_euler_and_back(normal):
"""
输入平面法向量,输出单位向量、欧拉角(XYZ顺序,角度制),并通过欧拉角重新计算单位向量
:param normal: 法向量(需满足ax+by+cz+d=0中的c=-1)
:return: 单位法向量、欧拉角(角度)、重构的单位向量
"""
# Step 1: 归一化法向量
normal = np.array(normal)
unit_normal = normal / np.linalg.norm(normal)
# Step 2: 构建旋转矩阵
target_z = unit_normal
# 定义临时参考轴(避免与法向量共线)
temp_x = np.array([1, 0, 0]) if not np.allclose(target_z, [1, 0, 0]) else np.array([0, 1, 0])
# 计算新的Y轴(正交化)
new_y = np.cross(target_z, temp_x)
new_y /= np.linalg.norm(new_y)
# 计算新的X轴
new_x = np.cross(new_y, target_z)
# 构建旋转矩阵
rotation_matrix = np.column_stack([new_x, new_y, target_z])
# Step 3: 转换为欧拉角(XYZ顺序,角度制)
rotation = Rotation.from_matrix(rotation_matrix)
euler_angles_deg = rotation.as_euler('xyz', degrees=True) # 直接输出角度
# Step 4: 从欧拉角(角度制)重构旋转矩阵并提取法向量
reconstructed_rotation = Rotation.from_euler('xyz', euler_angles_deg, degrees=True)
reconstructed_matrix = reconstructed_rotation.as_matrix()
reconstructed_normal = reconstructed_matrix[:, 2] # 第三列为Z轴方向
return unit_normal, euler_angles_deg, reconstructed_normal
# 示例测试
normal = np.array([7, 4, -1]) # 输入法向量(c=-1)
unit_normal, euler_angles_deg, reconstructed_normal = normal_to_euler_and_back(normal)
print("单位法向量:", unit_normal)
print("欧拉角(角度,XYZ顺序):", euler_angles_deg)
print("重构的单位法向量:", reconstructed_normal)