矢量旋转,分别以三角变换,矩阵变换实现,C#源码。

最近用到了图形旋转,花了不少时间查找材料,编码测试。而且还用到了20年前老师教给的三角函数,还有大学里面早已淡忘的矩阵运算。

呵呵,整理一下把,希望对大家有些帮助。

功能: 已知矢量OP,顺时针旋转α度,求P2点的坐标。

根据三角函数,我们可以很自然的写出:

P2.X = O.X + (int)(Math.Cos(alpha) * r) ;
P2.Y = O.Y + (int)(Math.Sin(alpha) * r) ;    //哦,代码的颜色怎么不变呢? 噢,因为我刚开始在博客园写博客,所有不会使,呵呵,懒得理它了。

可惜,这样写是不对的。 原因嘛,一共有四个象限啊,当P1在不同的象限时候,结果是不同的。 论证过程。。。省掉N字。

嗯,先说个定理,可能大家会用到:

如上,半径 r 知道了,旋转角也知道了,P1P2的长度是多少?

呵呵,献丑了,手绘的。

这个定理,可以帮我们得到边长,或者得到某边对应角的大小。 在我的项目里面用到了。

那么上面的P2点,究竟是多少? 哦,我就省去复杂的推理过程了,直接出代码:

 private Point GetNewPoint(double Rate, Point cirPos, Point startPos)
        {
            double Rage2 = Rate;// / 180 * Math.PI;
            //B点绕A点转R度得到C点坐标,flag: 顺时针1,反时针-1:B是转的点,A是圆心
            //C.X=(B.X-A.X)*COS(R*flag)-(B.Y-A.Y)*Sin(R*flag);
            //C.Y= (B.Y-A.Y)*COS(R*flag)+(B.X-A.X)*sin(R*flag);
            //转的点坐标-圆心坐标
            //圆心坐标+计算坐标=新位置的坐标
            double t1 = (startPos.X - cirPos.X) * Math.Cos(Rage2);
            double t2 = (startPos.Y - cirPos.Y) * Math.Sin(Rage2);
            int newx = (int)(t1 - t2);

            int newy = (int)((startPos.Y - cirPos.Y) * Math.Cos(Rage2) + (startPos.X - cirPos.X) * Math.Sin(Rage2));
            Point newpoint = new Point(cirPos.X + newx, cirPos.Y + newy);
            return newpoint;
        }

上面这个公式,不是个人推出来的,是教科书上的结论:

x0=|R|*cosA      y0=|R|*sinA                  x1 =|R|*cos(A +B)  y1=|R|*sin(A+B)

所以将x1,y1展开,有:

x1=|R|*(cosAcosB-sinAsinB)

y1=|R|*(sinAcosB+cosAsinB)

把    cosA = x0/|R|   sinA = y0/|R| 代入上面的式子,得到

 x1 = |R|*(x0*cosB/|R|-y0*sinB/|R|)

 y1 = |R|*(y0*cosB/|R|+x0*sinB/|R|)

最终结果:

x1 = x0 * cosB - y0 * sinB

y1 = x0 * sinB + y0 * cosB

呵呵,三角函数方式,代码与原理交代完毕。  下面就是矩阵了。

通常在二维中,我们使用的是三阶矩阵,为什么呢? 因为二阶不够使啊,为什么呢? 因为二阶只能实现:缩放,旋转,对称变换,无法实现平移啊,

为什么呢? 因为,二阶不是万能神啊,为什么呢?万能神是不问为什么的哈。。无语。

程序中矩阵的样子是这样的:

我们敲一个C#中的矩阵看看:

namespace System.Drawing.Drawing2D
{
    //
    // 摘要:
    //     封装表示几何变换的 3 x 3 仿射矩阵。此类不能被继承。
    public sealed class Matrix : MarshalByRefObject, IDisposable
    {
        //
        // 摘要:
        //     将 System.Drawing.Drawing2D.Matrix 类的一个新实例初始化为单位矩阵。
        public Matrix();

        public Matrix(RectangleF rect, PointF[] plgpts);
        //
        // 摘要:
        //     使用指定的元素初始化 System.Drawing.Drawing2D.Matrix 类的新实例。
        //
        // 参数:
        //   m11:
        //     新的 System.Drawing.Drawing2D.Matrix 的第一行和第一列中的值。
        //
        //   m12:
        //     新的 System.Drawing.Drawing2D.Matrix 的第一行和第二列中的值。
        //
        //   m21:
        //     新的 System.Drawing.Drawing2D.Matrix 的第二行和第一列中的值。
        //
        //   m22:
        //     新的 System.Drawing.Drawing2D.Matrix 的第二行和第二列中的值。
        //
        //   dx:
        //     新的 System.Drawing.Drawing2D.Matrix 的第三行和第一列中的值。
        //
        //   dy:
        //     新的 System.Drawing.Drawing2D.Matrix 的第三行和第二列中的值。
        public Matrix(float m11, float m12, float m21, float m22, float dx, float dy);

就是说,微软的matrix,我们可以定义为 x1 y1,x2 y2,x3 y3。 而微软会自动给我们补充第三列:0,0,1。这个查一下msdn就看到了。

哦,还是先上代码把,看看我们用matrix如何实现这种旋转。

        private void MyTest()
        {
            Point pa = new Point(100, 100);
            Point pb = new Point(200, 100);
            DrawPoint(Brushes.Red, pa);
            DrawPoint(Brushes.Black, pb);
            DrawLine(Pens.Red, pa, pb);

            double ang = Math.PI * 30 / 180;

            Matrix m = new Matrix();
            m.Translate(-pa.X, -pa.Y);
            m.Rotate(30, MatrixOrder.Append);
            m.Translate(pa.X, pa.Y, MatrixOrder.Append);

            Point[] ps = new Point[1];
            ps[0] = pb;

            m.TransformPoints(ps);
            DrawPoint(Brushes.Blue, ps[0]);

            Graphics g = Graphics.FromHwnd(this.Handle);
            Rectangle rect = new Rectangle(pa, new Size(0, 0));
            rect.Inflate(100, 100);           

            g.DrawArc(Pens.Red, rect, 0, 30);
            DrawPoint(Brushes.Green, ps[0]);
            DrawLine(Pens.Red, pa, ps[0]);

        }

        private void DrawPoint(Brush b, Point p)
        {
            Rectangle rect = new Rectangle(p, new Size(5, 5));
            Graphics g = Graphics.FromHwnd(this.Handle);
            g.FillRectangle(b, rect);
        }

        private void DrawLine(Pen pen, Point p1, Point p2)
        {
            Graphics g = Graphics.FromHwnd(this.Handle);
            g.DrawLine(pen, p1, p2);
        }

这段代码就可以实现第一幅图的效果了。

我们在百度上查资料,可以看到:缩放矩阵,旋转矩阵,平移矩阵。 但是,如果进行一个点,绕另外一个点进行旋转,那么这个操作就是一个复合矩阵操作,是组合变换方式。

在实际应用过程中,我们在使用word、ppt、photoshop,经常会把图片旋转一下,可能是以左上角为圆心,旋转20度,或者以图片中心点为圆心旋转。问题来了,我们用的圆心,不同于屏幕左上角的圆心哦,图片的四个角点的坐标,都是基于屏幕左上角圆心的坐标。这个怎么整?

是的,从O,到O1(哈哈,我上面画了O撇,输入法输不上,干嘛不画个O1啊,砸到自己脚啦),我们是平移了一个位移。所以我们如果想旋转P1后得到P2(呵呵,你懂的),

我们应当这样做:第一步:将O1移到O。  第二步:将坐标系旋转。第三步:将O1移回原来位置。 这样P2就完成了在坐标系 X1O1Y1中,从P1点转到P2点的任务。

第一步:平移变换:

第二步:旋转变换:

第三步:平移变换:

注意,矩阵乘法是讲究先后次序的,如同领导人的排名,不可乱来哦。 呼。。。小工告成,同志们吉祥。

时间: 2024-10-16 20:49:16

矢量旋转,分别以三角变换,矩阵变换实现,C#源码。的相关文章

下角动画旋转菜单、圆心弹出菜单ArcMenu 源码解析

支持类似Path的左下角动画旋转菜单及横向划出菜单.圆心弹出菜单 项目地址:https://github.com/daCapricorn/ArcMenu 一.关注3个效果 点击中心控制点 的时候,展开效果: 中心控制点旋转45度的动画 周围children 弹出动画 2.点击中心控制点的时候,收缩动画: 中心控制点旋转45度 周围children 自旋转并收缩 3.展开时候,点击child 被点击的child放大, 其他chidren 消失 二.3个java文件 ArcMenu.java  自定

旋转六面体源码

应网友要求,也方便大家一起学习,在此贴出昨天编写旋转六面体源码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>hexahedron</title> <meta

亚马逊左侧菜单延迟z三角 jquery插件jquery.menu-aim.js源码解读

关于亚马逊的左侧菜单延迟,之前一直不知道它的实现原理.梦神提到了z三角,我也不知道这是什么东西.13号那天很有空,等领导们签字完我就可以走了.下午的时候,找到了一篇博客:http://jayuh.com/amazon-site-navigation/ 它提到亚马逊左侧菜单的秘密在于它有一个三角形的缓冲延迟区域. 当鼠标在这个蓝色范围内移动时,会有延迟,所以右侧的二级菜单才不会马上变化. 顺着博客在github找到了这个插件:https://github.com/jayuh/jQuery-menu

三角形状的点阵模糊效果iOS源码

源码FFAngularPointilism,FFAngularPointilism能够将UIImageView像添加滤波器一样生成三角形状的点阵模糊效果.可以通过动画方式来模糊,也可以立刻模糊.另外并提供改模糊方式的动画.动画可以配置模糊程度及闪烁间隔.效果图: <ignore_js_op> 使用方法: 将Demo中的FFAngularPointilism文件夹直接复制到项目当中,并且将Images.xcassets中的4个三角形图案也要复制到项目中. 图像模糊 初始化: _imageView

浅谈RxJava源码解析(观察者),创建(create、from、just),变换(Map、flatMap)、线程调度

一.创建操作: 1.观察者模式:RxJava的世界里,我们有四种角色: Observable<T>(被观察者).Observer(观察者) Subscriber(订阅者).Subject Observable和Subject是两个"生产"实体,Observer和Subscriber是两个"消费"实体.Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Ob

iOS百思不得姐、ARKit、旋转动画、立体相册源码等

iOS精选源码 自定义视图弹出实现方案 仿写百思不得姐 ARKit,距离感应,AR尺子 iOS传感器集锦 AR太阳系,动画与光线处理,ARKit iOS启动页广告JYJAdViewController ThemeManager 是一个轻量级的主题管理库,使用简单方便无耦合 旋转跑马屏风动画Donut ARKit,AR尺子 3D立体可旋转相册 -- 原创应用:大杨子相册 iOS优质博客 iOS代码加固/混淆 众所周知的是大部分iOS代码一般不会做加密加固,因为iOS APP一般是通过AppStor

android-ImageView的拖动、旋转、缩放、边界回弹、双击缩放、单击销毁及源码下载

博客地址:http://blog.csdn.net/u010156024 TouchImageViewActivity 是本人一句一句代码写的,参考了网上大牛的博客. 不过其中的效果是网上没有的,也是本人一直想实现的效果. * 本实例重写ImageView的触摸事件和手势方法. * 实现图片的缩放.拖动,双击放大缩小.单击销毁,边界回弹,旋转并实现自动摆正. * 详细效果请看目录下面的:结果展示动态图.gif * 其中大部分关键节点都给出了注释,相信大家一看就会很快明白的. 本示例所展示的效果,

看我如何修改vlc2.1源码-libvlc录像 视频效果控制 旋转 图形 亮度 对比度 等控制

http://58.251.41.199:9200/upload/videoshow.wmv 上面地址是我整个做出来的视频演示效果.呵呵,达到了想要的效果,但是也牺牲了不小夜晚在linux上编译 1.首先你要找到增加libvlc的patch,修改源码.在官网上有,耐心找下. 2.一定要在unbuntu上编译vlc 3.要把他的vlc源码导出来理下其代码模块 搞好这几块,想咋改都行.想要源码可联系我396963546qq, 可以技术指导析,但是不会免费. 看我如何修改vlc2.1源码-libvlc

(素材源码)猫猫学IOS(三十六)UI之手势事件旋转_缩放_拖拽

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents 源码:http://download.csdn.net/detail/u013357243/8671943 效果 完成一个图片的捏合缩放,拖拽,旋转动作. 代码:NYViewController.m // // NYViewController.m // 旋转_缩放_拖拽 // // Created by apple on 1

openlayers6结合geoserver实现地图矢量瓦片(附源码下载)

内容概览 1.基于openlayers6结合geoserver实现地图矢量瓦片2.源代码demo下载 效果图如下: 实现思路:利用Geoserver发布矢量切片服务,然后openlayers调用矢量瓦片服务渲染加载,geoserver发布矢量服务步骤自行百度搜索相关教程,网上很多.最后,通过地图点击事件交互,实现图形高亮以及气泡窗口显示信息详情效果. 具体实现过程 利用geoserver发布好的矢量瓦片服务预览效果,直接F12看源码,来对应整合到demo var geojsonLayer = n