现在我已经使用以下功能在我的各种程序中围绕枢轴点旋转一系列点。
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)
只要我把它称之为一次就好了,它似乎也会逐渐变差,旋转度越低。函数中是否存在一些缺陷,或者我是否误解了这个函数的作用?
我怎么能少量反复旋转?我可以保存基点并使用它们在旋转变化时更新当前点,但这是唯一的方法吗?
答案 0 :(得分:2)
正如TaW正确指出的那样,由于head
方法生成的整数舍入,您的Point
位置指标已关闭。
使用RotatePoint()
坐标对方法返回值进行简单修正,将产生正确的度量:
要测试它,请创建一个计时器并将其float
事件注册为Tick
:
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
值会发生这种情况:
答案 1 :(得分:0)
如果您需要,可以使用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);