import numpy as np def hat(w): wx, wy, wz = w return np.array([[0, -wz, wy], [wz, 0, -wx], [-wy, wx, 0]], dtype=float) def rotvec_to_R(w): """Axis-angle (rotation vector) to rotation matrix.""" th = np.linalg.norm(w) if th < 1e-12: return np.eye(3) k = w / th K = hat(k) return np.eye(3) + np.sin(th) * K + (1-np.cos(th)) * (K @ K) def R_to_rotvec(R): """Rotation matrix to rotation vector (log map).""" tr = np.trace(R) cos_th = (tr - 1) / 2 cos_th = np.clip(cos_th, -1.0, 1.0) th = np.arccos(cos_th) if th < 1e-12: return np.zeros(3) w_hat = (R - R.T) / (2*np.sin(th)) return th * np.array([w_hat[2,1], w_hat[0,2], w_hat[1,0]]) def normalize(v, eps=1e-12): n = np.linalg.norm(v) if n < eps: return v*0.0 return v / n def clip(x, a, b): return max(a, min(b, x))