反复围绕枢轴点旋转点 [英] Rotate Point around pivot Point repeatedly
问题描述
一段时间以来,我一直在使用以下函数在我的各种程序中围绕枢轴点旋转一系列点.
For a while now I've been using the following function to rotate a series of Points around a pivot point in various programs of mine.
private Point RotatePoint(Point point, Point pivot, double radians)
{
var cosTheta = Math.Cos(radians);
var sinTheta = Math.Sin(radians);
var x = (cosTheta * (point.X - pivot.X) - sinTheta * (point.Y - pivot.Y) + pivot.X);
var y = (sinTheta * (point.X - pivot.X) + cosTheta * (point.Y - pivot.Y) + pivot.Y);
return new Point((int)x, (int)y);
}
一直很有效,直到我尝试反复旋转少量形状.例如,这是我在由4个点组成的矩形多边形上将其称为45°的结果:
This has always worked great, until I tried to rotate a shape repeatedly by small amounts. For example, this is what I get from calling it for 45° on a rectangular polygon made up of 4 points:
foreach (var point in points)
Rotate(point, center, Math.PI / 180f * 45);
但这就是我将45度旋转1度得到的结果:
But this is what I get by calling rotate 45 times for 1°:
for (var i = 0; i < 45; ++i)
foreach (var point in points)
Rotate(point, center, Math.PI / 180f * 1)
只要我称呼它一次就好,并且旋转度越低,它似乎就会变得越来越差.该功能是否存在缺陷,还是我误解了该功能的基本原理?
As long as I call it only once it's fine, and it also seems like it gets gradually worse the lower the rotation degree is. Is there some flaw in the function, or am I misunderstanding something fundamental about what this function does?
如何少量反复旋转?每当旋转改变时,我都可以保存基点并使用它们来更新当前点,但这是唯一的方法吗?
How could I rotate repeatedly by small amounts? I could save the base points and use them to update the current points whenever the rotation changes, but is that the only way?
推荐答案
正如TaW正确指出的那样,由于RotatePoint()
方法生成的整数舍入,您的Point
位置度量不可用.
As TaW correctly pointed out, your Point
position measure is off because of the integer rounding generated by the RotatePoint()
method.
使用float
坐标对方法的返回值进行简单的校正将产生正确的量度:
A simple correction in the method returned value, using float
coordinates, will produce the correct measure:
要对其进行测试,请创建一个计时器并将其Tick
事件注册为RotateTimerTick()
:
To test it, create a Timer and register its Tick
event as RotateTimerTick()
:
PointF PivotPoint = new PointF(100F, 100F);
PointF RotatingPoint = new PointF(50F, 100F);
double RotationSpin = 0D;
private PointF RotatePoint(PointF point, PointF pivot, double radians)
{
var cosTheta = Math.Cos(radians);
var sinTheta = Math.Sin(radians);
var x = (cosTheta * (point.X - pivot.X) - sinTheta * (point.Y - pivot.Y) + pivot.X);
var y = (sinTheta * (point.X - pivot.X) + cosTheta * (point.Y - pivot.Y) + pivot.Y);
return new PointF((float)x, (float)y);
}
private void RotateTimerTick(object sender, EventArgs e)
{
RotationSpin += .5;
if (RotationSpin > 90) RotationSpin = 0;
RotatingPoint = RotatePoint(RotatingPoint, PivotPoint, (Math.PI / 180f) * RotationSpin);
Panel1.Invalidate(new Rectangle(new Point(50,50), new Size(110, 110)));
}
private void Panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillEllipse(Brushes.White, new RectangleF(100, 100, 8, 8));
e.Graphics.FillEllipse(Brushes.Yellow, new RectangleF(RotatingPoint, new SizeF(8, 8)));
}
这是使用float
值的结果:
This is the result using float
values:
这是使用integer
值发生的情况:
And this is what happens using integer
values:
这篇关于反复围绕枢轴点旋转点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!