两个向量对的四元数

3

我有两组向量(旋转前和旋转后)。

旋转前: [x1,y1,z1] [x2,y2,z2]

旋转后: [x1',y1',z1'] [x2',y2',z2']

如何创建表示此旋转的四元数?

5个回答

3
大多数情况下,没有旋转可以将2个向量转换为另外2个向量。这是一个简单的可视化方式:旋转不会改变向量之间的角度。如果旋转前2个向量之间的角度与旋转后2个向量之间的角度不同,则不存在符合您标准的旋转。
尽管如此,可能存在一种最佳四元数,其具有可接受的误差,可以“几乎”旋转您的2个向量对。有许多算法可用于查找此类四元数,这些算法在速度和精度上有所不同。我为Arduino应用编写了一个快速的C++算法,其中速度至关重要,但精度不太重要。
链接:http://robokitchen.tumblr.com/post/67060392720/finding-a-rotation-quaternion-from-two-pairs-of-vectors 旋转前:u0,v0。旋转后:u2,v2。
Quaternion q2 = Quaternion::fromTwoVectors(u0, u2);
Vector v1 = v2.rotate(q2.conjugate());
Vector v0_proj = v0.projectPlane(u0);
Vector v1_proj = v1.projectPlane(u0);
Quaternion q1 = Quaternion::fromTwoVectors(v0_proj, v1_proj);
return (q2 * q1).normalized();

如果这不能满足你的应用需求,尝试谷歌“Wabha问题”。

2

我将marcv81非常有帮助的博客文章翻译成了Three.js:

const rotateVectorsSimultaneously = (u0, v0, u2, v2) => {
    const q2 = new THREE.Quaternion().setFromUnitVectors(u0, u2);

    const v1 = v2.clone().applyQuaternion(q2.clone().conjugate());

    const v0_proj = v0.projectOnPlane(u0);
    const v1_proj = v1.projectOnPlane(u0);

    let angleInPlane = v0_proj.angleTo(v1_proj);
    if (v1_proj.dot(new THREE.Vector3().crossVectors(u0, v0)) < 0) {
        angleInPlane *= -1;
    }
    const q1 = new THREE.Quaternion().setFromAxisAngle(u0, angleInPlane);

    const q = new THREE.Quaternion().multiplyQuaternions(q2, q1);
    return q;
};

由于 angleTo 总是返回正值,我需要手动翻转角度的符号,具体取决于 v1u0-v0 平面的哪一侧。

1

首先,您可以使用向量乘法(叉乘)找到旋转轴:

axis = v1 x v2;

然后您可以计算旋转角度:

sinA = |axis| / |v1|*|v2|
cosA = v1 . v2 / |v1|*|v2|

这里的 || 表示向量长度操作,. 表示点乘

最终,你的四元数是:

Q(w,x,y,z) = (cosA, axis.x * sinA, axis.y * sinA, axis.z * sinA)

1
好的,谢谢。我认为这个方法不一定返回满足两个向量旋转的旋转。 - undefined
因为Dorian提到的原因,答案是错误的,所以被投下了反对票。 - undefined
余弦相似度计算时,您不会失去所在象限的信息吗? - undefined

0

从v1到v2找到四元数是可以的。

最终的q = (cos A/2, sin A/2 * axis),其中A是v1和v2之间的角度,axis是归一化的轴。

两边都乘以2 * cos A/2,

然后我们有 2 * cos A/2 *q = (1+cos A, sin A * axis)

(其中cos A = dot(v1, v2)/|v1|/|v2|axis = cross(v1, v2).normalize() = cross(v1, v2)/|v1|/|v2|/sin A.)

然后2 * cos A/2 *q = (1+dot(v1, v2)/|v1|/|v2|, cross(v1, v2)/|v1|/|v2|)

最后q = (1+dot(v1, v2)/|v1|/|v2|, cross(v1, v2)/|v1|/|v2|).normalize()


0
这个问题的成熟解决方案被称为Triad。Triad是太空飞行器姿态确定问题最早和最简单的解决方案之一,计算效率非常高。
使用Triad,思路是将你原来的成对的两个向量替换为一组成对的三个向量,其中额外的向量通过叉乘生成。通过对向量进行归一化,你可以解得一个旋转矩阵而无需矩阵求逆或奇异值分解(在更一般的问题实例中需要,参见瓦巴问题)。
完整的算法请参见:https://en.wikipedia.org/wiki/Triad_method 然后,你可以将从Triad解得的旋转矩阵转换为一个旋转四元数:
qw = √(1 + m00 + m11 + m22) /2
qx = (m21 - m12)/( 4 *qw)
qy = (m02 - m20)/( 4 *qw)
qz = (m10 - m01)/( 4 *qw)

通常,为了使四元数的转换更加稳健,您应该考虑查看矩阵的迹,如此处所讨论的:http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/

最后,考虑使用直接计算最优四元数的Triad的替代方法,称为QUEST


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接