如何计算 C# 中的旋转图像坐标?

How to count rotated image coordinates in C#?

我正在编写程序通过使用 x y 坐标在图片框中绘制图像来绘制一些线条。图像将是可调整的,因此可以调整大小或旋转,但我希望绘制的线条跟随图像,而不是停留在图片框坐标上。当放大或缩小时,线条仍然跟随图像,但旋转时它随机跳跃而不是跟随图像。

绘制 3 条线的默认程序

缩放后的图像,线条仍然存在

图像旋转 10 度。线条跳转到随机位置。

我目前正在使用这个带有 2 个坐标的坐标来形成一条线,但它使坐标随机地到处跳跃,而不是随图像一起旋转。 这是黑线 1 的代码。

---编辑---

这是顺时针旋转的代码,但不知何故它逆时针旋转。 angle2 的值仍然未知,32 是通过逆时针旋转一个一个地尝试的最接近的位置。坐标没有像以前那样随机跳跃,现在它随着图片旋转,但旋转的位置仍然不正确。旋转 360 度后,坐标位置与原始位置略有移动。每次旋转都是逆时针的。

在角度 2

中以 32 值旋转之前的原始值

旋转360度后

float x = (float)bmp.Width / 2;
float y = (float)bmp.Height / 2;
ang = ang + 10;
double ang2 = 32;
double newLine1X1 =  (line1X1 - x) * Math.Cos(ang2 /180) + (line1Y1 - y) * Math.Sin(ang2 /180) + x;
double newLine1Y1 = -(line1X1 - x) * Math.Sin(ang2 /180) + (line1Y1 - y) * Math.Cos(ang2 /180) + y;
double newLine1X2 =  (line1X2 - x) * Math.Cos(ang2 /180) + (line1Y2 - y) * Math.Sin(ang2 /180) + x;
double newLine1Y2 = -(line1X2 - x) * Math.Sin(ang2 /180) + (line1Y2 - y) * Math.Cos(ang2 /180) + y;
line1X1 = (int)newLine1X1;
line1Y1 = (int)newLine1Y1;
line1X2 = (int)newLine1X2;
line1Y2 = (int)newLine1Y2;

顺时针旋转代码

float x = (float)bmp.Width / 2;
float y = (float)bmp.Height / 2;
ang = ang - 10;
double ang2 = -32;
double newLine1X1 = (line1X1 - x) * Math.Cos(ang2 /180) - (line1Y1 - y) * Math.Sin(ang2 /180) + x;
double newLine1Y1 = (line1X1 - x) * Math.Sin(ang2 /180) + (line1Y1 - y) * Math.Cos(ang2 /180) + y;
double newLine1X2 = (line1X2 - x) * Math.Cos(ang2 /180) - (line1Y2 - y) * Math.Sin(ang2 /180) + x;
double newLine1Y2 = (line1X2 - x) * Math.Sin(ang2 /180) + (line1Y2 - y) * Math.Cos(ang2 /180) + y;
line1X1 = (int)newLine1X1;
line1Y1 = (int)newLine1Y1;
line1X2 = (int)newLine1X2;
line1Y2 = (int)newLine1Y2;

逆时针旋转代码

谁能告诉我如何解决这个旋转错误?非常感谢你。

你要的是一个变换矩阵和一个偏移向量

https://en.wikipedia.org/wiki/Transformation_matrix#Rotation

P_x为点P的x坐标,P_y为其y坐标

PT_x 和 PT_y 应为变换后的坐标

O_x和O_y为偏移点(图片旋转的点)

d 应为旋转角度...

PT_x =  (P_x - O_x) * cos(d) + (P_y - O_y) * sin(d) + O_x
PT_y = -(P_x - O_x) * sin(d) + (P_y - O_y) * cos(d) + O_y

示例:一个旋转的盒子,在盒子旋转时有一条线指向同一点

using System;
using System.Drawing;
using System.Windows.Forms;

namespace SoExamples.Rotation
{
    public  class Form1 : Form
    {
        Bitmap bmp = new Bitmap(100, 100); //placeholder... our rotating box
        Point p1 = new Point(80,5);//a point in our rotating box
        int deg = 0;//the current rotation of the box in degrees 0...359
        Point start;//a point to start drawing a line...


        public Form1()
        {
            InitializeComponent();

            //preparing our dummy box
            using (var graphics = Graphics.FromImage(bmp))
            {
                graphics.Clear(Color.LightBlue);// a background color...
                graphics.DrawString("X", DefaultFont, Brushes.White, p1);
            }

            //calculating the start point for a line...
            start = new Point(label1.Location.X + label1.Width / 2, label1.Location.Y + label1.Height); //in the middle under the label
        }
        /// <summary>
        /// timer handler, executed every time the timer is ellapsed ... every 100ms
        /// </summary>
        private void timer1_Tick(object sender, EventArgs e)
        {
            deg++;//let's rotate...
            deg %= 360;//0...359
            Invalidate(true);//queue for re-drawing
        }

        /// <summary>
        /// custom painting for the Form ... called every time the form is re-drawn
        /// </summary>
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            var g = e.Graphics;

            g.Clear(BackColor);

            Point drawTo = new Point(Width / 2, Height / 2);//we want to draw the box in the center of the form
            drawTo.Offset(-bmp.Width / 2, -bmp.Height / 2);//...but we need to specify the upper left corner

            Point rotateAround = new Point(Width / 2, Height / 2);//we want to rotate the box around the center

            g.TranslateTransform(-rotateAround.X, -rotateAround.Y); //translate the rotateAround point as 0,0
            g.RotateTransform(-deg, System.Drawing.Drawing2D.MatrixOrder.Append);//rotate
            g.TranslateTransform(rotateAround.X, rotateAround.Y, System.Drawing.Drawing2D.MatrixOrder.Append);//translate back

            g.DrawImageUnscaled(bmp, drawTo);//draw the box with respect to current transforms... 

            g.ResetTransform();//now back to our original coordinate-space

            var P = new Point(drawTo.X + p1.X, drawTo.Y + p1.Y); //the point we want to point to in the original coordinate-space (before rotation)

            var O = rotateAround;
            var rad = deg * Math.PI / 180d; //System.Math want's our angle in radians 

            //coordinate calculation for a rotation around O
            //PT_x = (P_x - O_x) * cos(d) + (P_y - O_y) * sin(d) + O_x
            //PT_y = -(P_x - O_x) * sin(d) + (P_y - O_y) * cos(d) + O_y

            var PT_x = (P.X - O.X) * Math.Cos(rad) + (P.Y - O.Y) * Math.Sin(rad) + O.X;
            var PT_y = -(P.X - O.X) * Math.Sin(rad) + (P.Y - O.Y) * Math.Cos(rad) + O.Y;

            drawTo = new Point((int)PT_x, (int)PT_y);

            g.DrawLine(Pens.Black, start, drawTo); // draw a line to the calculated point

        }

        //boiler plate code follows...

        private System.ComponentModel.IContainer components = null;
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.label1 = new System.Windows.Forms.Label();
            this.timer1 = new System.Windows.Forms.Timer(this.components);
            this.SuspendLayout();
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(41, 43);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(197, 13);
            this.label1.TabIndex = 1;
            this.label1.Text = "Some fixed point to start drawing a line to the top left corner of a 'X' in a rotating box...";
            // 
            // timer1
            // 
            this.timer1.Enabled = true;
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Controls.Add(this.label1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Timer timer1;
    }
}