【问题标题】:Quaternion and axis of rotation四元数和旋转轴
【发布时间】:2013-01-29 10:04:45
【问题描述】:

这个问题已经回答了。下面是使它工作所需的大部分代码!希望对其他人有所帮助。

感谢@Aki Suihkonen、@David Hammen 和@MBo。

两个角度函数都给出了正确的答案。

我有三点:

A: 12 4 5
B: 6 8 -10
C: 5 6 7

我已经实现了四元数。我想旋转 C 点,使 Angle( A, B, C ) 比以前高 40 度。

我的问题是:我必须根据哪个轴旋转?我想象因为 A、B 和 C 创建了一个平面,所以我必须根据向量 BA 和 BC 的垂直轴旋转点 C。我用它们的单位向量的 CrossProduct 得到它,但是当我尝试得到 Angle( A, B, C ) 时,它并没有给我正确的结果。

这是我获得角度的方式:(旧方法)

results:
Angle of ABC before rotation = 67.3895.
Angle of ABC after rotation = 107.389.

float Angle( float x1, float y1, float z1,
             float x2, float y2, float z2 )
{
  float x, y, z;
  CrossProduct( x1, y1, z1, x2, y2, z2, &x, &y, &z );

  float result = atan2 ( L2Norm( x, y, z ),
                         DotProduct( x1, y1, z1, x2, y2, z2 ) );

  return result;
}

其中 x1, y1, z1, x2, y2, z2 是单位向量 B-A 和 B-C 的结果。

更新角度功能:

results:
Angle of ABC before rotation = 67.3895.
Angle of ABC after rotation = 107.389.

Angle( Atom &atom1, Atom &atom2, Atom &atom3 )
{
float px1, py1, pz1;
    float px2, py2, pz2;

    UnitVector( atom1.X(), atom1.Y(), atom1.Z(),
            atom2.X(), atom2.Y(), atom2.Z(),
            &px1, &py1, &pz1 );


    UnitVector( atom3.X(), atom3.Y(), atom3.Z(),
            atom2.X(), atom2.Y(), atom2.Z(),
            &px2, &py2, &pz2 );

  float dot_product = DotProduct( px1, py1, pz1, px2, py2, pz2 );
  float length_BA = sqrt( px1*px1 + py1*py1 + pz1*pz1 );
  float length_BC = sqrt( px2*px2 + py2*py2 + pz2*pz2 );

  return acos( dot_product / ( length_BA * length_BC ) );
}

float DotProduct( float x1, float y1, float z1,
                  float x2, float y2, float z2 )
{
  return x1*x2 + y1*y2 + z1*z2;
}

void CrossProduct( float x1, float y1, float z1,
                   float x2, float y2, float z2,
                   float *ox, float *oy, float *oz )
{
  *ox = (y1*z2) -(z1*y2);
  *oy = -((x1*z2) -(z1*x2));
  *oz = (x1*y2) -(y1*x2);
}

所以我的问题是:我必须根据哪个轴旋转点 C,这样 Angle(A,B,C) 会比以前大 40 度?

  // The 3 points.
  Atom A( "A", -4, 2 , 8 );
  Atom B( "B", -1, 3 , 4 );
  Atom C( "C", -2, -4 , 5 );

  float x1, y1, z1;
  float x2, y2, z2;
  float x, y, z;

  // Get the cross product. Create the perpendicular vector to the BA and BC vectors.
  PointVector( A.X(), A.Y(), A.Z(), B.X(), B.Y(), B.Z(), &x1, &y1, &z1 );
  PointVector( C.X(), C.Y(), C.Z(), B.X(), B.Y(), B.Z(), &x2, &y2, &z2 );

  CrossProduct( x1, y1, z1, x2, y2, z2, &x, &y, &z );

  // Normalize the coordinates.
  float length = sqrt( x*x + y*y + z*z );
  length = 1.0 / length;

  x *= length;
  y *= length;
  z *= length;

  // Create the 40 degrees angle. It is supposed to increment the current ABC angle by 40 degrees.
  float angle = 40*M_PI/180;
  float sinAngleOver2 = sin(angle/2);
  float w = cos(angle/2);

  // Create the axis quat.
  Quatd q(w, x * sinAngleOver2, y * sinAngleOver2, z * sinAngleOver2);

  // Create the point quaternal. The angle of it equals to the current ABC angle.
  angle = Angle( A, B, C ) *180/M_PI;
  angle *= M_PI/180;
  sinAngleOver2 = sin(angle/2);
  w = cos(angle/2);

  // Normalize the coordinates. The coordinates are the C point coordinates.


    x = C.X() - B.X();
    y = C.Y() - B.Y();
    z = C.Z() - B.Z();

    length = sqrt( x*x + y*y + z*z );
    length = 1.0 / length;

    x *= length;
    y *= length;
    z *= length;


  Quatd qpt(w, x * sinAngleOver2, y * sinAngleOver2, z * sinAngleOver2);

  // Rotate.
  qpt = q*qpt*q.unitInverse();

  Atom new_C;
  new_C.X( qpt.x + B.X() );
  new_C.Y( qpt.y + B.Y() );
  new_C.Z( qpt.z + B.Z() );

  cout << "Angle: " << Angle( A, B, new_C )*180/M_PI << '\n';

【问题讨论】:

  • 您是在记录角度算法还是您的意思是如果我删除 L2Norm 我会得到我想要的结果?
  • 函数 L2Norm 有什么作用?您可以将角度计算为 result = arccos(DotProduct( x1, y1, z1, x2, y2, z2 )/ (BA.Length*CA.Length))
  • 不确定。它的 atan2 公式是这样解释的。我相信我在其中一个 matlab 论坛中看到了它。至于轴,你有解决方案吗?
  • 鉴于名称,我强烈怀疑L2Norm 会计算输入向量的 [1=L2 norm]。换句话说,它计算向量的欧几里得长度。 [1]mathworld.wolfram.com/L2-Norm.html
  • 您没有显示如何旋转 C 的代码,所以这只是一个猜测:您正在旋转 C 关于原点。那不是你想做的。您需要围绕 B 旋转 C。

标签: c++ math 3d rotation quaternions


【解决方案1】:

此代码不正确:

// Normalize the coordinates. The coordinates are the C point coordinates.
length = sqrt( C.X()*C.X() + C.Y()*C.Y() + C.Z()*C.Z() );
length = 1.0 / length;

x = C.X() / length;
y = C.Y() / length;
z = C.Z() / length;

重用length 变量来存储1 / length,您已经把自己弄糊涂了。您需要将C 的分量乘以length 以在此处标准化您的向量。

我对四元数数学不够熟悉,无法理解您最后要做什么,但看起来您确实在围绕原点旋转 C。您想围绕B 旋转,这意味着从C 中减去B,围绕原点执行旋转,然后将B 添加到结果中以返回到原始空间。

就我个人而言,我会实现某种四元数向量乘法,或者将四元数转换为矩阵以执行转换。

【讨论】:

  • 胜利!非常感谢。现在可以了。我将使用正确的代码更新主帖,以便每个人都能受益。如果这是reddit,我会向所有人投赞成票!
猜你喜欢
  • 1970-01-01
  • 2011-05-25
  • 2011-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
相关资源
最近更新 更多