用C#实现计算机图形学算法

    多数情况下计算机图形学算法都用C++实现,下面鄙人用C#实现一部分算法。并附上运行截图。

一 图案

1 金刚石

    金刚石图案是每一个顶点都与其他顶点相连的正n边形。金刚石图案有时被用作计算机图形设备的测试图案。通过观察交汇于每个顶点的直线所呈现出来的拥挤和模糊程度,可以确定设备的分辨率。

    做程序时,使用线段连接每个顶点时不进行重复连接。

    主要代码如下:

            //n为等分点的个数,r为圆的半径
            Pen p = new Pen(Color.Blue, 1);//定义了一个蓝色,宽度为的画笔
            double Thta;//thta为圆的等分角
            Thta = 2 * PI / jgsn;
            for (int i = 0; i < jgsn; i++)
            {
                pt[i].X = (int)(r * Math.Cos(i * Thta) + maxX / 2);
                pt[i].Y = (int)(r * Math.Sin(i * Thta) + maxY / 2);
            }
            for (int i = 0; i <= jgsn - 2; i++)
            {
                for (int j = i + 1; j <= jgsn - 1; j++)
                {
                    //dc.MoveTo(ROUND(pt3[i].x),ROUND(pt3[i].y));
                    //g.DrawLine(p,pt[i],pt[j]);
                    g.DrawLine(p, pt[i].X, pt[i].Y, pt[j].X, pt[j].Y);
                    //dc.LineTo(ROUND(pt3[j].x),ROUND(pt3[j].y));
                }
            }

 

运行结果如下:

 

    金刚石图案按孔令德老师所说,等分点数为奇数时图案中心为一个圆,等分点数为偶数时图案中心为一个点,运行结果确实如此。

2 Menger海绵

    将一个立方体沿其各个面三等分为27个小立方体,舍弃位于体心的一个小立方体,以及位于立方体六个面心处的6个小立方体。将剩余的20个小立方体继续按相同的方法分割与舍弃,就能得到中间有大量空隙的Menger海绵。

    算法步骤:

    输入递归深度n;

    绘制初始立方体;

    将立方体的每条边三等分,舍弃6个位于面心的小立方体和一个位于体心处的小立方体,使用画家算法绘制余下的20个小立方体;

    执行递归子程序,对其余20个小立方体进行递归,直到n为0。

 

    具体代码就不贴出了,有兴趣可以自己下载了查看;运行效果如下;

 

    绘图时可以用C#的Point类型的数组表示点集,如果用C++的话通常需要自己定义一个二维点类。在编写图形学算法代码时,还会用到三维点类,这就需要自己定义了。

    另外C#的二维数组定义与C++颇有不同,其定义类似如下;

 private int[,] TM=new int[4,4];//变换矩阵

    二维数组作函数参数的写法则类似如下,与C++不同;

private void KeepOriginalMatrix(int[,] Orig,int[,] Dest)

 

二 基本图元算法

1 圆中点Bresenham算法

    Bresenham算法是计算机图形学领域使用广泛的直线扫描转换方法。其原理是:过各行、各列像素中心构造一组虚拟网格线,按直线从起点到终点的顺序计算直线各垂直网格线的交点,然后确定该列像素中与此交点最近的像素。

    此处为了清楚演示计算机图形学的原理,并不画计算出的每一个点,而是先生成Button的控件数组,在每个点处放一个小Button,Button的长和宽为10;这样出来的效果相当于把屏幕单个像素放大了10倍;如下图所示;

    设置Button数组坐标的代码如下,其他部分可自行下载查看;

private void CirclePoint(int x, int y,int cnt)//八分法画圆子函数
        {
      
            btny[0 + 8 * cnt].Left = x + maxX / 2 - 8;
            btny[0 + 8 * cnt].Top = y + maxY / 2 - 8;
            btny[1 + 8 * cnt].Left = y + maxX / 2 - 8;
            btny[1 + 8 * cnt].Top = x + maxY / 2 - 8;
            btny[2 + 8 * cnt].Left = y + maxX / 2 - 8;
            btny[2 + 8 * cnt].Top = -x + maxY / 2 - 8;
            btny[3 + 8 * cnt].Left = x + maxX / 2 - 8;
            btny[3 + 8 * cnt].Top = -y + maxY / 2 - 8;


            btny[4 + 8 * cnt].Left = -x + maxX / 2 - 8;
            btny[4 + 8 * cnt].Top = -y + maxY / 2 - 8;
            btny[5 + 8 * cnt].Left = -y + maxX / 2 - 8;
            btny[5 + 8 * cnt].Top = -x + maxY / 2 - 8;
            btny[6 + 8 * cnt].Left = -y + maxX / 2 - 8;
            btny[6 + 8 * cnt].Top = x + maxY / 2 - 8;
            btny[7 + 8 * cnt].Left = -x + maxX / 2 - 8;
            btny[7 + 8 * cnt].Top = y + maxY / 2 - 8;


        }

 

三 二维变换

1 首先绘制坐标系和基本图形

 

2 二维变换是通过矩阵运算完成的

    相关代码如下;

private void DrawShape(Graphics g) //画四边形
        {
            
            KeepOriginalMatrix(P24, OSquare);
            Pen pen = new Pen(Color.Green, 2);
            g.DrawLine(pen, maxX / 2 + P24[0, 0], maxY / 2 - P24[0, 1], maxX / 2 + P24[1, 0], maxY / 2 - P24[1, 1]);
            g.DrawLine(pen, maxX / 2 + P24[1, 0], maxY / 2 - P24[1, 1], maxX / 2 + P24[2, 0], maxY / 2 - P24[2, 1]);
            g.DrawLine(pen, maxX / 2 + P24[2, 0], maxY / 2 - P24[2, 1], maxX / 2 + P24[3, 0], maxY / 2 - P24[3, 1]);
            g.DrawLine(pen, maxX / 2 + P24[3, 0], maxY / 2 - P24[3, 1], maxX / 2 + P24[0, 0], maxY / 2 - P24[0, 1]);


        }


        private void KeepOriginalMatrix(int[,] Orig,int[,] Dest)//保留矩阵
        {
       int i,j;
       for(i=0;i<4;i++)
       for(j=0;j<3;j++)
       Dest[i,j]=Orig[i,j];
        }


        private void Tmove(int Tx,int Ty)//平移变换矩阵
        {
       ClearMatrix(TM);
       TM[0,0]=1;
       TM[1,1]=1;
       TM[2,0]=Tx;
       TM[2,1]=Ty;
       TM[2,2]=1;
       Calculate(P24,TM);
            
        }


        private void Trotate(double thta)//旋转变换矩阵
        {
       ClearMatrix(TR2);
       TR2[0,0]=(int) Math.Cos(thta*PI/180);
            TR2[0, 1] = (int)Math.Sin(thta * PI / 180);
            TR2[1, 0] = (int) -Math.Sin(thta * PI / 180);
            TR2[1, 1] = (int)Math.Cos(thta * PI / 180);
       TR2[2,2]=1;
       Calculate(P24,TR2);
       
        }


        private void Tscale(double Sx,double Sy)//比例变换矩阵
        {
       ClearMatrix(TS2);
       TS2[0,0]=(int)Sx;
       TS2[1,1]=(int)Sy;
       TS2[2,2]=1;
       Calculate(P24,TS2);
       
        }


        private void Treform(double b,double c)//错切变换矩阵
        {
       ClearMatrix(TC2);
       TC2[0,0]=1;
       TC2[0,1]=(int)b;
       TC2[1,0]=(int)c;
            TC2[1,1]=1;
       TC2[2,2]=1;
       Calculate(P24,TC2);
       
        }


        private void ClearMatrix(int[,] A)//清除变换矩阵
        {
       for(int i=0;i<3;i++)
       {
       for(int j=0;j<3;j++)
       A[i,j]=0;
       }
        }


        private void Calculate(int[,] P0,int[,] T)//两个矩阵相乘
        {
       int[,] Ptemp=new int[4,3];
       KeepOriginalMatrix(P24,Ptemp);
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    P24[i, j] = Ptemp[i, 0] * T[0, j] + Ptemp[i, 1] * T[1, j] + Ptemp[i, 2] * T[2, j];
                }
            }
        }

 

下面是平移,缩放,错切的运行结果;从菜单中画初始图形;用四个方向键实现平移;用M键实现放大;用C和D键实现2个方向的错切;

 

 

 

四 基本三维

1 画一个三维立方体

    主要代码如下;

private void DrawCube(Graphics g)//绘制立方体
        {
       Point[] p=new Point[4];//定义多边形顶点数组
       Transform3DTo2D(P3D,P2D,8);
       //绘制立方体左面
       p[0]=new Point(maxX/2+P2D[0,0],(maxY/2+P2D[0,1]));
       p[1]=new Point(maxX/2+P2D[3,0],(maxY/2+P2D[3,1]));
       p[2]=new Point(maxX/2+P2D[7,0],(maxY/2+P2D[7,1]));
       p[3]=new Point(maxX/2+P2D[4,0],(maxY/2+P2D[4,1]));
            Pen  pen = new  Pen(Color.Blue, 2);
            g.DrawLines(pen, p);
            //绘制立方体后面
       p[0]=new Point(maxX/2+P2D[0,0],(maxY/2+P2D[0,1]));
       p[1]=new Point(maxX/2+P2D[1,0],(maxY/2+P2D[1,1]));
       p[2]=new Point(maxX/2+P2D[2,0],(maxY/2+P2D[2,1]));
       p[3]=new Point(maxX/2+P2D[3,0],(maxY/2+P2D[3,1]));
            g.DrawLines(pen, p);
       //绘制立方体底面
       p[0]=new Point(maxX/2+P2D[0,0],(maxY/2+P2D[0,1]));
       p[1]=new Point(maxX/2+P2D[4,0],(maxY/2+P2D[4,1]));
       p[2]=new Point(maxX/2+P2D[5,0],(maxY/2+P2D[5,1]));
            p[3]=new Point(maxX/2+P2D[1,0],(maxY/2+P2D[1,1]));
            g.DrawLines(pen, p);
       //绘制立方体右面
       p[0]=new Point(maxX/2+P2D[1,0],(maxY/2+P2D[1,1]));
       p[1]=new Point(maxX/2+P2D[2,0],(maxY/2+P2D[2,1]));
       p[2]=new Point(maxX/2+P2D[6,0],(maxY/2+P2D[6,1]));
       p[3]=new Point(maxX/2+P2D[5,0],(maxY/2+P2D[5,1]));
            g.DrawLines(pen, p);
       //绘制立方体顶面
       p[0]=new Point(maxX/2+P2D[3,0],(maxY/2+P2D[3,1]));
       p[1]=new Point(maxX/2+P2D[7,0],(maxY/2+P2D[7,1]));
       p[2]=new Point(maxX/2+P2D[6,0],(maxY/2+P2D[6,1]));
       p[3]=new Point(maxX/2+P2D[2,0],(maxY/2+P2D[2,1]));
            g.DrawLines(pen, p);
       //绘制立方体前面
       p[0]=new Point(maxX/2+P2D[4,0],(maxY/2+P2D[4,1]));
       p[1]=new Point(maxX/2+P2D[5,0],(maxY/2+P2D[5,1]));
       p[2]=new Point(maxX/2+P2D[6,0],(maxY/2+P2D[6,1]));
       p[3]=new Point(maxX/2+P2D[7,0],(maxY/2+P2D[7,1]));
            g.DrawLines(pen, p);
        }

效果如下;

 

代码和可执行文件下载:

http://pan.baidu.com/s/1hqF0Jic

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值