C# 围绕轴心点重复旋转点

C# 围绕轴心点重复旋转点,c#,rotation,drawing,point,C#,Rotation,Drawing,Point,一段时间以来,在我的各种程序中,我一直在使用以下函数围绕轴心点旋转一系列点 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

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

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°得到的结果:

foreach (var point in points)
    Rotate(point, center, Math.PI / 180f * 45);

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

for (var i = 0; i < 45; ++i)
    foreach (var point in points)
        Rotate(point, center, Math.PI / 180f * 1)
for(变量i=0;i<45;++i)
foreach(变量点到点)
旋转(点、中心、Math.PI/180f*1)

只要我只叫它一次就好了,而且旋转度越低,情况似乎也会越来越糟。该函数是否存在一些缺陷,或者我是否误解了该函数的基本功能


我怎么能以少量重复旋转?我可以保存基点,并在旋转发生变化时使用它们更新当前点,但这是唯一的方法吗?

如果需要,可以使用Media3D仅处理矩阵并简化编码。像这样简单的事情就行了

public Point3D Rotate(Point3D point, Point3D rotationCenter, Vector3D rotation, double degree)
{
    // create empty matrix
    var matrix = new Matrix3D();

    // translate matrix to rotation point
    matrix.Translate(rotationCenter - new Point3D());

    // rotate it the way we need
    matrix.Rotate(new Quaternion(rotation, degree));

    // apply the matrix to our point
    point = matrix.Transform(point);

    return point;
}
然后您只需调用该方法并指定旋转。假设您使用2D(如示例中所示),并假设我们使用XY平面,因此旋转在Z方向。您可以执行以下操作:

var rotationPoint = new Point3D(0, 0, 0);
var currentPoint = new Point3D(10, 0, 0);

// rotate the current point around the rotation point in Z by 45 degree
var newPoint = Rotate(currentPoint, rotation, new Vector3D(0, 0, 1), 45d);

正如TaW正确指出的,由于
RotatePoint()
方法生成的整数舍入,您的
位置度量值已关闭。

使用
float
坐标对方法返回值进行简单更正,将生成正确的度量值:

要对其进行测试,请创建一个计时器,并将其
勾号
事件注册为
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
值得出的结果:


这就是使用
integer
值时发生的情况:



你能换成F点吗?谢谢你的回答,在这里查看答案之前,我刚刚意识到了这一点。这么愚蠢的小错误。