先明确变换含义
跳转到“先明确变换含义”给定非零向量 ,希望一个主动旋转矩阵 R 使原 z 轴 指向 ,即 。本文保持世界参考系不变,旋转三根基向量;R 的三列就是旋转后的 x、y、z 轴。若要把世界中的坐标改写到旋转后的坐标系,使用的是 。
只给定 z 轴方向不能唯一决定完整姿态,还可以绕新 z 轴任意旋转。这里额外选择转角最小的解;恰好反向时最小转角为 π,旋转轴仍不唯一。
一般情况的推导
跳转到“一般情况的推导”对单位向量 a、b:
当 ,单位旋转轴 ,转角取 。令 K 为叉乘矩阵,满足 ,则 Rodrigues 公式为:
原代码使用与此等价的 形式,却除以 ,未处理平行向量,因而同向、反向时都会出现除零。
NumPy 实现
跳转到“NumPy 实现”import numpy as np
def align_z_to_negative(vector): v = np.asarray(vector, dtype=float) if v.shape != (3,) or not np.all(np.isfinite(v)): raise ValueError("vector must contain three finite numbers") scale = np.max(np.abs(v)) if scale == 0: raise ValueError("zero vector has no direction")
# 先缩放,避免对极大或极小输入直接求模时溢出/下溢。 v = v / scale b = -v / np.linalg.norm(v) a = np.array([0.0, 0.0, 1.0]) w = np.cross(a, b) s = np.linalg.norm(w) c = np.clip(np.dot(a, b), -1.0, 1.0) if s < 1e-12: if c > 0: return np.eye(3) # 反向时任选与 z 垂直的轴;这里绕 x 轴旋转 pi。 return np.diag([1.0, -1.0, -1.0])
k = w / s K = np.array([[0.0, -k[2], k[1]], [k[2], 0.0, -k[0]], [-k[1], k[0], 0.0]]) return np.eye(3) + s * K + (1.0 - c) * (K @ K)1e-12 是本例处理浮点近平行情况的容差,不是所有应用的统一要求。验证时检查 、、。
四元数与欧拉角
跳转到“四元数与欧拉角”若安装 SciPy,可由矩阵转换:
from scipy.spatial.transform import Rotation
R = align_z_to_negative([1, 1, 1])rotation = Rotation.from_matrix(R)q_xyzw = rotation.as_quat()angles_xyz = rotation.as_euler("xyz", degrees=True)as_quat() 默认返回标量在后的 (x,y,z,w),不应直接当作 (w,x,y,z) 传给别的库。小写 xyz 表示外禀旋转序列;欧拉角有奇异性,万向节锁时不能唯一分解三个角,但旋转矩阵仍可有效。四元数、欧拉角

原始记录
跳转到“原始记录”本笔记由 CSDN 原始记录 的文字与图片重新整理;正文中的代码、适用条件与说明已按本次审读补充。