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

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

问题描述

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

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

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