2D欧几里得向量旋转

59

我有一个欧几里得向量a,位于坐标(0, 1)处。 我想要将a绕原点(0, 0)旋转90度(顺时针)。

如果我对此如何运作有正确的理解,则旋转后的结果(x,y)坐标应为(1, 0)。 如果我选择将其旋转45度(仍然顺时针),我期望的结果坐标将是(0.707, 0.707)

theta = deg2rad(angle);

cs = cos(theta);
sn = sin(theta);

x = x * cs - y * sn;
y = x * sn + y * cs;

使用上述代码,当 angle 值为 90.0 度时,结果坐标为: (-1, 1)。 我真是太困惑了。 以下链接中的示例肯定代表了上面显示的相同公式吧?

我做错了什么? 还是我误解了矢量旋转的方式?


所有变量的类型是什么? - Oliver Charlesworth
浮点数,但答案足够简单,感谢 Caspar。 - deceleratedcaviar
2
这个也不是逆时针吗? - Nick Pruehs
5个回答

111

旋转向量90度特别简单。

(x, y) 围绕 (0, 0) 旋转90度,结果为 (-y, x)

如果你想逆时针旋转,只需反过来即可得到 (y, -x)


47
对于任何旋转计算机屏幕上的2D向量的人:本答案假设y轴向上,如数学中一样。如果y轴向下,就像在计算机屏幕上一样,则顺时针和逆时针方向相反。(-y,x)是顺时针方向,(y,-x)是逆时针方向。 - Jordan Miner

93

你应该从函数中移除变量:

x = x * cs - y * sn; // now x is something different than original vector x
y = x * sn + y * cs;

创建新的坐标,以避免在达到第二行之前计算x:

px = x * cs - y * sn; 
py = x * sn + y * cs;

4
哦天啊,我需要新鲜的眼睛……又是这么明显的事情……谢谢伙计(非常有效,两个小时后...哈哈) - deceleratedcaviar
当您执行 x = x * cs - y * sn; 时,它会给 x 赋一个不同的值,而在 y = x * sn + y * cs 中,x 将会 "脱轨"。 - Caspar Kleijne
2
@Daniel:第二个语句中的x在你计算y值时已经被改变了。因此,实际上,你计算的是(0,1)旋转后的x坐标(即-1)。然后,你将其存储在x坐标中得到了(-1,1),并且你计算的是旋转后(-1,1)的y坐标(实际应该是-1,所以我不确定你是怎么得到(-1,1)而不是(-1,-1)的)。顺便说一下,正确的答案不是(1,0),而是(-1,0),因为从上面看旋转正角是逆时针方向。 - Keith Irwin
2
这个YouTube系列视频将为您深入而直观地解释旋转/基变换的概念! - CPayne

25

绕着0,0旋转90度:

x' = -y
y' = x

绕着 px,py 旋转90度:

x' = -(y - py) + px
y' = (x - px) + py

7

使用标准类更容易实现:

std::complex<double> vecA(0,1);
std::complex<double> i(0,1); // 90 degrees
std::complex<double> r45(sqrt(2.0),sqrt(2.0));
vecA *= i;
vecA *= r45;

向量旋转是复数乘法的一个子集。要旋转角度为alpha,您需要乘以std::complex<double> { cos(alpha), sin(alpha) }


请注意,此方法无需计算正弦或余弦。 - Jeff Linahan
2
说实话,那是因为 r45 是预先计算的。 - MSalters

5
您正在根据新坐标的“新”x部分计算其y部分。基本上,这意味着您正在根据新输出计算新输出...请尝试以输入和输出的术语重写此内容:
vector2<double> multiply( vector2<double> input, double cs, double sn ) {
  vector2<double> result;
  result.x = input.x * cs - input.y * sn;
  result.y = input.x * sn + input.y * cs;
  return result;
}

然后你可以这样做:
vector2<double> input(0,1);
vector2<double> transformed = multiply( input, cs, sn );

注意如何为变量选择适当的名称可以完全避免这个问题!

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