勇哥先来谈谈点绕原点旋转
如下图, 在2维坐标上,有一点p(x, y) , 直线opの长度为r, 直线op和x轴的正向的夹角为a。 直线op围绕原点做逆时针方向b度的旋转,到达p’ (s,t)
s = r cos(a + b) = r cos(a)cos(b) – r sin(a)sin(b) (1.1)
t = r sin(a + b) = r sin(a)cos(b) + r cos(a) sin(b) (1.2)
其中 x = r cos(a) , y = r sin(a)
代入(1.1), (1.2) ,
s = x cos(b) – y sin(b) (1.3)
t = x sin(b) + y cos(b) (1.4)
用行列式表达如下:
由于勇哥数学底子差,不知道式1是怎么来的,它其实是cos(a+b)的展开式:
cos(a+b)=cosacosb-sinasinb 顺便附上所有形式 sin(A+B) = sinAcosB+cosAsinB sin(A-B) = sinAcosB-cosAsinB cos(A+B) = cosAcosB-sinAsinB cos(A-B) = cosAcosB+sinAsinB
下面应用上面的旋转公式写个C#例子:
private void button4_Click(object sender, EventArgs e) { for(int i=0;i<pointa.Length;i++) { pointa[i] = rotate30(pointa[i]); } draw(pointa); } Point rotate30(Point a) //旋转30度 { double c = 30 * Math.PI / 180.0; int x = a.X; int y = a.Y; a.X = Convert.ToInt32(x * Math.Cos(c) - y * Math.Sin(c)); a.Y = Convert.ToInt32(x * Math.Sin(c) + y * Math.Cos(c)); return a; } void draw(Point[] pointm) { //原点移动到215,215 g = this.pictureBox1.CreateGraphics(); g.Clear(this.pictureBox1.BackColor); g.TranslateTransform(265, 245); g.DrawLine(new Pen(new SolidBrush(Color.Black)), new Point(-300, 0), new Point(300, 0)); g.DrawLine(new Pen(new SolidBrush(Color.Black)), new Point(0, -300), new Point(0, 300)); g.DrawPolygon(new Pen(new SolidBrush(Color.Blue)), pointm); g.Dispose(); }
以上程序,每按一次旋转,多边形从当前位置转30度。
下面勇哥谈谈利用矩阵来旋转点
把上面的行列式写成矩阵的方式是这样的:
但这是一个2*2矩阵,无法表示平移操作。
在计算机图形学中,为了统一将平移、旋转、缩放等用矩阵表示,需要引入齐次坐标。(假设使用2x2的矩阵,是没有办法描述平移操作的,只有引入3x3矩阵形式,才能统一描述二维中的平移、旋转、缩放操作。同理必须使用4x4的矩阵才能统一描述三维的变换)。
由于引入了齐次坐标,在描述二维坐标的时候,使用(x,y,w)的方式(一般w=1),于是可以写成下面矩阵的形式。
于是我们可以把上面的2*2旋转矩阵扩展成下面这样的3*3矩阵。
勇哥写了一段C#代码测试一下这个旋转矩阵:
public static List<Point> RotateTrans(List<Point> points, double angel) { /* * 旋转的变换矩阵 * * cos sin 0 * -sin cos 0 * 0 0 1 * * 点 * * X * Y * 1 * * **/ double sinA = Math.Sin(angel * Math.PI / 180); double cosA = Math.Cos(angel * Math.PI / 180); // angel为正数即说明相对原点顺时针 double[] Rdata = new double[] { cosA, sinA, 0, -sinA, cosA, 0, 0, 0, 1 }; Matrix R = new Matrix(3, Rdata); // 3*3 矩阵 // 输出当前变换矩阵 Console.WriteLine("旋转的变换矩阵为: \n" + R.ToString()); // 变换 points = Trans(points, R); return points; } public static List<Point> Trans(List<Point> points, Matrix trans) { // 遍历List<Point> 对每一个点都变换 for (int i = 0; i < points.Count; ++i) { double[] Pdata = new double[] { points[i].X, points[i].Y, 1 }; Matrix P = new Matrix(3, 1, Pdata); Console.WriteLine("之前P: \n" + P.ToString()); // 矩阵的乘法 (即变换) P = trans * P; Console.WriteLine("之后P: \n" + P.ToString()); // 将当前更新后的点替换原先的点 // 四舍五入 int x = Round_Int(P.GetElement(0, 0)); int y = Round_Int(P.GetElement(1, 0)); points[i] = new Point(x, y); } return points; } private void button5_Click(object sender, EventArgs e) { draw(RotateTrans(pointa.ToList(), 30).ToArray()); }
如果想顺时针转动,则修改矩阵为:
cosA, -sinA, 0, sinA, cosA, 0
或者把旋转角度写成-30度。
程序中的类Matrix不是微软的类库,它是netMarketing类库v1.3.1中的一个类。
你也可以网上搜索一下矩阵的类库。
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

