围绕枢轴点重复旋转点 [英] Rotate Point around pivot Point repeatedly

查看:31
本文介绍了围绕枢轴点重复旋转点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一段时间以来,我一直在使用以下函数在我的各种程序中围绕轴心点旋转一系列点.

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);

但这就是我通过调用 1° 旋转 45 次得到的结果:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆