You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何求解绕非正交向量c、a的旋转角度以得到目标向量v的朝向

非正交双轴旋转角度求解方案

前提约定

  • 所有参与计算的向量(c、a、初始参考向量v₀、目标向量v)均先做单位归一化处理,朝向计算不受长度影响
  • 旋转顺序固定为:先绕c轴旋转θ(对应RotationC)得到中间向量v₁,再绕a轴旋转φ(对应RotationA)得到目标向量v
  • 罗德里格斯旋转公式:绕单位轴u旋转α角后的向量为 v' = v*cosα + (u×v)*sinα + u*(u·v)*(1-cosα)

求解步骤

步骤1:求解绕c轴的旋转角θ

绕a轴旋转不会改变向量与a的点积,因此可得到仅含θ的约束方程:
(R(c,θ) * v₀) · a = v · a
将罗德里格斯公式代入后整理为三角函数标准形式:
A*cosθ + B*sinθ = C
其中各系数计算方式:

  • A = Vector3.Dot(v0, a) - Vector3.Dot(c, a) * Vector3.Dot(c, v0)
  • B = Vector3.Dot(Vector3.Cross(c, v0), a)
  • C = Vector3.Dot(v, a) - Vector3.Dot(c, a) * Vector3.Dot(c, v0)

求解该方程即可得到θ,方程通解为:
θ = Atan2(B, A) ± Acos(C / sqrt(A² + B²))
可根据实际业务场景选择符合预期的解即可,若C² > A²+B²说明目标向量v无法通过该双轴旋转得到。

步骤2:求解绕a轴的旋转角φ

代入已求得的θ,用罗德里格斯公式计算得到中间向量v₁:
v1 = RotateAroundAxis(v0, c, θ)
将v₁和v分别投影到垂直于a的平面上,消除a方向分量的影响:

  • p1 = v1 - a * Vector3.Dot(v1, a)
  • p2 = v - a * Vector3.Dot(v, a)
    若p1、p2的模长接近0,说明v与a平行,φ可取任意默认值(通常设为0);否则对p1、p2做归一化后,构造正交基计算φ:
  • x = Vector3.Cross(a, p1)
  • RotationA = Math.Atan2(Vector3.Dot(p2, x), Vector3.Dot(p2, p1))

参考实现(C#风格)

// 工具方法:绕指定轴旋转向量
Vector3 RotateAroundAxis(Vector3 vec, Vector3 axis, double angle)
{
    double cos = Math.Cos(angle);
    double sin = Math.Sin(angle);
    double dot = Vector3.Dot(vec, axis);
    Vector3 cross = Vector3.Cross(axis, vec);
    return vec * cos + cross * sin + axis * dot * (1 - cos);
}

// 主求解逻辑
(double RotationC, double RotationA) SolveRotationAngles(Vector3 c, Vector3 a, Vector3 v0, Vector3 v)
{
    // 预处理:所有向量归一化
    c = Vector3.Normalize(c);
    a = Vector3.Normalize(a);
    v0 = Vector3.Normalize(v0);
    v = Vector3.Normalize(v);

    // 计算系数求解θ
    double ca = Vector3.Dot(c, a);
    double cv0 = Vector3.Dot(c, v0);
    double A = Vector3.Dot(v0, a) - ca * cv0;
    double B = Vector3.Dot(Vector3.Cross(c, v0), a);
    double C = Vector3.Dot(v, a) - ca * cv0;

    double sqrtAB = Math.Sqrt(A * A + B * B);
    if (sqrtAB < 1e-6 || Math.Abs(C) > sqrtAB + 1e-6)
    {
        throw new ArgumentException("目标朝向无法通过当前双轴旋转得到");
    }
    double alpha = Math.Atan2(B, A);
    double beta = Math.Acos(Math.Clamp(C / sqrtAB, -1, 1));
    // 此处取第一个解,可根据需求调整为减beta的解
    double theta = alpha + beta;

    // 求解φ
    Vector3 v1 = RotateAroundAxis(v0, c, theta);
    Vector3 p1 = v1 - a * Vector3.Dot(v1, a);
    Vector3 p2 = v - a * Vector3.Dot(v, a);
    if (p1.Length() < 1e-6 || p2.Length() < 1e-6)
    {
        return (theta, 0);
    }
    p1 = Vector3.Normalize(p1);
    p2 = Vector3.Normalize(p2);
    Vector3 x = Vector3.Cross(a, p1);
    double phi = Math.Atan2(Vector3.Dot(p2, x), Vector3.Dot(p2, p1));

    return (theta, phi);
}

参考示意图

参考示意图

内容的提问来源于stack exchange,提问作者PetrasVestartasEPFL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 21:18:04