用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
?
總結
以上是生活随笔為你收集整理的用C#实现计算机图形学算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图解MySQL删除再安装教程
- 下一篇: Spire.XLS试用手记