当前位置: 首页 > news >正文

计算机图形学实习教程之基本图形的生成(二维图形裁剪Cohen-Sutherland算法+图形平移算法+图形旋转算法),利用C#实现,附源码

环境:Win10+Visual Studio 2022 Community

在本次实验中需要用到第一篇文章实验内容的代码及环境,详情请见:传送门

目录

一、实验目的

二、实验步骤

1.Cohen-Sutherland算法

2.平移算法

3.旋转算法


一、实验目的

1.熟练掌握二维图形裁剪的Cohen-Sutherland算法

2.熟练掌握图形的平移算法

3.熟练掌握图形的旋转算法

二、实验步骤

1.Cohen-Sutherland算法

(1)打开工程项目,在菜单项“二维裁剪图形”下建立子菜单“Cohen算法”,在其属性窗口将属性项Name的属性值改为“CohenCut”。

(2)双击菜单项“Cohen算法”,系统建立一个空的菜单响应函数CohenCut_Click。在该函数中加入如下语句:

        private void CohenCut_Click(object sender, EventArgs e)
        {
            MenuID = 21; PressNum = 0;
            Graphics g = CreateGraphics();  //创建图形设备
            XL = 100; XR = 400; YD = 100; YU = 400; //窗口参数
            pointsgroup[0] = new Point(XL, YD);
            pointsgroup[1] = new Point(XR, YD);
            pointsgroup[2] = new Point(XR, YU);
            pointsgroup[3] = new Point(XL, YU);
            g.DrawPolygon(Pens.Blue, pointsgroup);  //创建裁剪窗口
        }

(3)用MenuID变量表示后续的操作都与该算法有关,因为要使用鼠标,因此初始化PressNum变量。用四个变量记录窗口参数,因为其他的很多算法也要使用窗口,因此将这四个变量变为Form类变量,为此要对Form类变量做添加如下;为了方便使用图形相关函数画窗口,设置了一个包含四个点的数组pointsgroup。由于其他算法也需要事先画窗口,将这个数组同样设置为Form类变量公共变量:

        public int MenuID, PressNum, FirstX, FirstY, OldX, OldY, XL, XR, YU, YD;
        Point[] pointsgroup = new Point[4]; //创建一个有4个点的点数组

(4)在Form1_MouseClick函数中,增加菜单指示变量MenuID为21(即开始 Cohen-Sutherland裁剪算法)时的程序操作语句如下:

            if (MenuID == 21)   //Cohen裁剪算法
            {
                if (PressNum == 0)  //保留第一点
                {
                    FirstX = e.X;
                    FirstY = e.Y;
                    PressNum++;
                }
                else    //第二点,调用裁剪算法
                {
                    CohenCut1(FirstX, FirstY, e.X, e.Y);  //Cohencut裁剪
                    PressNum = 0; //清零,为画下一次裁剪做准备
                }
            }

(5)函数CohenCut1是在窗口参数和线段参数都已获取的前提下实现Cohen-Sutherland 裁剪算法的函数。在窗体实现程序Form1.cs中插入以下函数:

        private void CohenCut1(int x1, int y1, int x2, int y2)
        {
            int code1 = 0, code2 = 0, code, x = 0, y = 0;
            Graphics g = CreateGraphics();  //创建图形设备
            g.DrawLine(Pens.Red, x1, y1, x2, y2);   //画原始线段
            code1 = encode(x1, y1); //对线段端点编码
            code2 = encode(x2, y2);
            while (code1 != 0 || code2 != 0)
            {
                if ((code1 & code2) != 0) return;   //完全不可见
                code = code1;
                if (code1 == 0) code = code2;
                if ((1 & code) != 0)    //求线段与窗口左边的交点:0001=1
                {
                    x = XL;
                    y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
                }
                else if ((2 & code) != 0)
                {
                    x = XR;
                    y = y1 + (y2 - y1) * (x - x1) / (x2 - x1);
                }
                else if ((4 & code) != 0)
                {
                    y = YD;
                    x = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
                }
                else if ((8 & code) != 0)
                {
                    y = YU;
                    x = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
                }
                if (code == code1)
                {
                    x1 = x;
                    y1 = y;
                    code1 = encode(x, y);
                }
                else
                {
                    x2 = x;
                    y2 = y;
                    code2 = encode(x, y);
                }
            }
            Pen MyPen = new Pen(Color.Black, 3);
            g.DrawLine(MyPen, x1, y1, x2, y2);
        }

(6)其中,函数encode的功能是对线段的一个端点进行编码,目前还没有,需要立即实现。如果严格按照算法描述方法逐个生成每个裁剪线段端点4个二进制码位,编程繁复。这里根据窗口参数先确定9个区域,然后根据端点落在哪个区域直接赋予编码。encode函数实现如下:

        private int encode(int x, int y)
        {
            int code = 0;
            if (x >= XL && x <= XR && y >= YD && y <= YU) code = 0; //窗口区域:0000
            if (x < XL && y >= YD && y <= YU) code = 1; //窗口左区域:0001
            if (x > XR && y >= YD && y <= YU) code = 2; //窗口右边域:0010
            if (x >= XL && x <= XR && y > YU) code = 8; //窗口上区域:1000
            if (x >= XL && x <= XR && y < YD) code = 4; //窗口下区域:0100
            if (x <= XL && y > YU) code = 9; //窗口左上区域:1001
            if (x >= XR && y > YU) code = 10; //窗口右上区域:1010
            if (x <= XL && y < YD) code = 5; //窗口左下区域:0101
            if (x >= XR && y < YD) code = 6; //窗口右下区域:0110
            return code;
        }

(6)运行结果

2.平移算法

(1)在菜单项“二维图形变换”下添加子菜单项“图形平移”,将其属性项Name的属性值改为英文字符“TransMove”。

(2)双击菜单项建立菜单响应函数,在系统建立的空的响应函数TransMove_Click中加入语句如下:

        private void TransMove_Click(object sender, EventArgs e)
        {
            MenuID = 11;
            PressNum = 0;
            Graphics g = CreateGraphics();  //创建图形设备
            pointsgroup[0] = new Point(100, 100);   //设置变换图形
            pointsgroup[1] = new Point(200, 100);
            pointsgroup[2] = new Point(200, 200);
            pointsgroup[3] = new Point(100, 200);
            g.DrawPolygon(Pens.Red, pointsgroup);   //显示图形
        }

(3)平移量用鼠标操作确定,即用鼠标先后确定两个点,第二点减去第一点的坐标增量就是平移量,将坐标增量分别加到原图形坐标上,就得到平移以后的图形,显示这个图形,就完成了平移变换,具体做法是在Form1_MouseClick函数中加入如下语句:

            if (MenuID == 11)   //平移
            {
                if (PressNum == 0)  //保留第一点
                {
                    FirstX = e.X;
                    FirstY = e.Y;
                }
                else    //第二点,确定平移量,改变图形参数
                {
                    for (int i = 0; i < 4; i++)
                    {
                        pointsgroup[i].X += e.X - FirstX;
                        pointsgroup[i].Y += e.Y - FirstY;
                    }
                    g.DrawPolygon(Pens.Blue, pointsgroup);
                }
                PressNum++;
                if (PressNum >= 2)
                {
                    PressNum = 0;           //完毕,清零,为下一次做准备
                }
            }

(4)运行结果

3.旋转算法

(1)在菜单项“二维图形变换”下建立子菜单项“图形旋转”,将其属性项Name的属性值改为英文字符“TransRotate”。

(2)双击菜单项建立菜单响应函数TransRotate_Click。在系统建立的空的响应函数中加入语句如下:

        private void TransRotate_Click(object sender, EventArgs e)
        {
            MenuID = 12;
            PressNum = 0;
            Graphics g = CreateGraphics();  //创建图形设备
            pointsgroup[0] = new Point(100, 100);
            pointsgroup[1] = new Point(200, 100);
            pointsgroup[2] = new Point(200, 200);
            pointsgroup[3] = new Point(100, 200);
            g.DrawPolygon(Pens.Red, pointsgroup);   //画出被旋转图形
        }

(3)在Form1_MouseClick函数中加入处理旋转的鼠标操作指令如下:

if (MenuID == 12)   //旋转
            {
                if (PressNum == 0)  //保留第一点
                {
                    FirstX = e.X;
                    FirstX = e.Y;
                }
                else    //第二点,确定旋转角度,改变图形参数
                {
                    double a;
                    if (e.X == FirstX && e.Y == FirstY) return; //排除两点重合的异常情况
                    if (e.X == FirstX && e.Y > FirstY)  //排除分母为0的异常情况
                    {
                        a = 3.1415926 / 2.0;
                    }
                    else if (e.X == FirstX && e.Y < FirstY)
                    {
                        a = 3.1415926 / 2.0 * 3.0;
                    }
                    else
                    {
                        //计算旋转弧度
                        a = Math.Atan((double)(e.Y - FirstY) / (double)(e.X - FirstX));
                    }
                    a = a / 3.1415926 * 180.0;  //弧度转化为角度
                    int x0 = 150, y0 = 150; //指定旋转中心
                    Matrix myMatrix = new Matrix(); //创建矩阵对象,以利用矩阵工具
                    myMatrix.Translate(-x0, -y0);   //创建平移量为(-x0,-y0)的平移矩阵
                    myMatrix.Rotate((float)a, MatrixOrder.Append);  //右乘角度为a的旋转矩阵
                    myMatrix.Translate(x0, y0, MatrixOrder.Append); //右乘平移量为(x0,y0)的平移矩阵
                    g.Transform = myMatrix;     //用复合矩阵变换图形设备
                    g.DrawPolygon(Pens.Blue, pointsgroup);  //显示旋转结果
                }
                PressNum++;
                if (PressNum >= 2)
                {
                    PressNum = 0;           //完毕,清零,为下一次做准备
                }
            }

(4)为了能够直接使用系统提供的矩阵设置、计算、处理工具,我们需要引进定义了矩阵的命名空间,添加语句如下:

using System.Drawing.Drawing2D;

(5)运行结果

相关文章:

  • 上海网站建设褐公洲司/代写平台
  • wordpress点赞/百度收录情况查询
  • wordpress resize/seo高级教程
  • quadrum wordpress/国外网站
  • 做外卖网站的模板/品牌广告投放
  • 找做网站的/网络营销就业前景和薪水
  • 计算机网络概括
  • 关于MySQL中的存储引擎
  • 外部链接<a>
  • 1.3笔记
  • ## Leetcode刷题Day24-------------------回溯算法
  • 普冉PY32系列(三) PY32F002A资源实测 - 这个型号不简单
  • grpc、https、oauth2等认证专栏实战19:docker启动tls配置介绍
  • 2个大厂 100亿级 超大流量 红包 架构方案
  • 2023/1/15 JS-变量提升与函数提升 执行上下文
  • 基于transfomer架构的模型[GPT、BERT、VIT、ST、MAE等等]总结
  • 基于51单片机的pm2.5空气质量监测仪仿真设计
  • Java使用Zxing二维码生成