導航:首頁 > 源碼編譯 > 中點直線畫圓演算法

中點直線畫圓演算法

發布時間:2022-08-27 12:24:40

『壹』 計算機圖形學復習

第一章
1. 計算機圖形:用數學方法描述,通過計算機生成、處理、存儲和顯示的對象。
2. 圖形和圖像的主要區別是表示方法不同:圖形是用矢量表示;圖像是用點陣表示的。圖形和圖像也可以通過光柵顯示器(或經過識別處理)可相互轉化。
3. 於計算機圖形學緊密相關的學科主要包括 圖像處理、計算幾何和計算機視覺模式識別。它們的共同點是 以圖形/圖像在計算機中的表示方法為基礎。
4. 互動式計算機圖形系統的發展可概括為以下4個階段:字元、矢量、二維光柵圖形、三維圖形。
5. 圖形學研究的主要內容有:①幾何造型技術 ②圖形生成技術 ③圖形處理技術 ④圖形信息的存儲、檢索與交換技術 ⑤人機交互技術 ⑥動畫技術 ⑦圖形輸入輸出技術 ⑧圖形標准與圖形軟體包的研發。
6. 計算機輔助設計和計算機輔助製造 是計算機圖形學最廣泛最活躍的應用領域。
7. 計算機圖形學的基本任務:一是如何利用計算機硬體來實現圖形處理功能;二是如何利用好的圖形軟體;三是如何利用數學方法及演算法解決實際應用中的圖行處理問題。
8. 計算機圖形系統是由硬體系統和軟體系統組成的。
9. 計算機圖形系統包括處理、存儲、交互、輸入和輸出五種基本功能。
10. 鍵盤和滑鼠是最常用的圖形輸入設備。滑鼠根據測量位移部件的不同,分為光電式、光機式和機械式3種。
11. 數字化儀分為電子式、超聲波式、磁伸縮式、電磁感應式等。小型的數字化儀也稱為圖形輸入板。
12. 觸摸屏是一種 定位設備,它是一種對於觸摸能產生反應的屏幕。
13. 掃描儀由3部分組成:掃描頭、控制電路和移動掃描機構。掃描頭由光源發射和光鮮接收組成。按移動機構的不同,掃描儀可分為平板式和滾筒式2種。
14. 顯示器是計算機的標准輸出設備。彩色CRT的顯示技術有2種:電子穿透法和蔭罩法。
15. 隨機掃描是指電子束的定位及偏轉具有隨意性,電子束根據需要可以在熒光屏任意方向上連續掃描,沒有固定掃描線和掃描順序限制。它具有局部修改性和動態性能。
16. 光柵掃描顯示器是畫點設備。
17. 點距是指相鄰像素點間的距離,與分辨指標相關。
18. 等離子顯示器一般有三層玻璃板組成,通常稱為等離子顯示器的三層結構。
19. 用以輸出圖形的計算機外部設備稱為硬拷貝設備。
20. 列印機是廉價的硬拷貝設備,從機械動作上常為撞擊式和非撞擊式2種。
21. 常用的噴墨頭有:壓電式、氣泡式、靜電式、固體式。
22. 繪圖儀分為靜電繪圖儀和筆式繪圖儀。
23. 圖形軟體的分層。由下到上分別是:①圖形設備指令、命令集、計算機操作系統 ②零級圖形軟體 ③一級圖形軟體 ④二級圖形軟體 ⑤三級圖形軟體。
24. 零級圖形軟體是面向系統的、最底層的軟體,主要解決圖形設備與主機的通信與介面問題,又稱設備驅動程序。
25. 一級圖形軟體即面向系統又面向用戶,又稱基本子系統。
26. 圖形應用軟體是系統的核心部分。
27. 從物理學角度,顏色以主波長、色純度和輝度來描述;從視覺角度來看,顏色以色彩、飽和度和亮度來描述。
28. 用適當比列的3種顏色混合,可以獲得白色,而且這3種顏色中的任意2種的組合都不能生成第三種顏色,稱為三原色理論。
29. RGB模型的匹配表達式是:c=rR+gG+bB。
30. 常用顏色模型
顏色模型名稱 使用范圍
RGB 圖形顯示設備(彩色CRT和光柵顯示器)
CMY 圖形列印、繪制設備
HSV 對應畫家本色原理、直觀的顏色描述
HSL 基於顏色參數的模型
用基色青、品紅、黃定義的CMY顏色模型用來描述硬拷貝設備的輸出顏色。它從白光中濾去某種顏色,故稱為減色性原色系統。

第二章
31. 直線生成的3個常用演算法:數值微分法(DDA)、中點劃線法和Bresenham演算法。
32. DDA演算法的C語言實現:
DDA演算法生成直線,起點(x0,y0),終點(x1,y1).
Void CMy View ::OnDdaline()
{
CDC *pDC=GetDC(); //獲得設備指針
int x0=100,y0=100,x1=300,y1=200,c=RGB(250,0,0);//定義直線兩端點和直線顏色
int x,y,i;
float dx,dy,k;
dx=(float)(x1-x0);
dy=(float)(y1-y0);
k=dy/dx;
x=x0;
y=y0;
if(abs(k)<1)
{ for(;x<=x1;x++)
{pDC—>SetPixel(x,int(y+0.5),c);
y=y+k;}
}
if(abs(k)>=1)
{ for(;y<=y1;y++)
{pDC—>SetPixel(int(x+0.5),y,c);
x=x+1/k;}
}
ReleaseDC(pDC); //釋放設備指針
}
33. 任何影響圖元顯示方法的參數稱為屬性參數。圖元的基本表現是線段,其基本屬性包括線型、線寬和色彩。
34. 最常見的線型包括實線、虛線、細線和點劃線等,通常默認的線型是實線。
35. 線寬控制的實線方法:垂直線刷子、水平線刷子、方形線刷子。生成具有寬度的線條還可以採用區域填充演算法。
36. 用離散量表示連續量時引起的失真現象稱為走樣。為了提高圖形顯示質量,減少或消除走樣現象的技術稱為反走樣。
37. 反走樣技術有:提高解析度(硬體方法和軟體方法)、簡單區域取樣、加權區域取樣。
38. 區域連通情況分為四連通區域和八連通區域。四連通區域是指從區域上某一點出發,可通過上下左右4個方向移動,在不越出區域的前提下到達區域內的任意像素;八連通區域是指從區域內某一像素出發,可通過上下左右、左上左下、右上右下8個方向的移動,在不越出區域的前提下到達區域內的任意像素。
39. 字元的圖形表示可以分為點陣式和矢量式兩種形式。
40. 在圖形軟體中,除了要求能生成直線、圓等基本圖形元素外,還要求能生成其他曲線圖元、多邊形及符號等多種圖元。
41. 在掃描線填充演算法中,對水平邊忽略而不予處理的原因是實際處理時不計其交點。
42. 關於直線生成演算法的敘述中,正確的是:Bresenham演算法是對中點畫線演算法的改進。
43. 在中點畫圓演算法中敘述錯誤的是:為了減輕畫圓的工作量,中點畫圓利用了圓的四對稱性性質。
44. 多邊形填充時,下列論述錯誤的是:在判斷點是否在多邊形內時,一般通過在多變形外找一點,然後根據該線段與多邊形的交點數目為偶數即可認為在多邊形內部,若為奇數則在多邊形外部,且不考慮任何特殊情況。
第三章
1. Cohen-Sutherland演算法,也稱編碼裁剪法。其基本思想是:對於每條待裁剪的線段P1P2分三種情況處理:①若P1P2完全在窗口內,則顯示該線段,簡稱「取」之;②若P1P2完全在窗口外,則丟棄該線段,簡稱「舍」之;③若線段既不滿足「取」的條件也不滿足「舍」的條件,則求線段與窗口邊界的交點,在交點處把線段分為兩段,其中一段 完全在窗口外,可舍棄之,然後對另一段重復上述處理。
2. Sutherland-Hodgman演算法,又稱逐邊裁剪演算法。其基本思想是用窗口的四條邊所在的直線依次來裁剪多邊形。多邊形的每條邊與裁剪線的位置關系有4種情況(假設當前處理的多邊形的邊為SP):a>端點S在外側,P在內側,則從外到內輸出P和I;b>端點S和P都在內側,則從內到內輸出P;c>端點S在內側,而P在外側,則從內到外輸出I;d>端點S和P都在外側,無輸出。
3. 按裁剪精度的不同,字元裁剪可分為三種情況:字元串裁剪、字元裁剪和筆畫裁剪。
4. 在線段AB的編碼裁剪演算法中,如A、B兩點的碼邏輯或運算全為0,則該線段位於窗口內;如AB兩點的碼邏輯與運算結果不為0,則該線段在窗口外。
5. n邊多邊形關於矩形窗口進行裁剪,結果多邊形最多有2n個頂點,最少有n個頂點。
6. 對一條等長的直線段裁剪,編碼裁剪演算法的速度和中點分割演算法的裁剪速度哪一個快,無法確定。(√)
7. 多邊形裁剪可以看做是線段裁剪的組合。(X)
8. 對於線段來說,中點分割演算法要比其他線段裁剪演算法的裁剪速度快。(X)
9. 多邊形的Weiler-Atherton裁剪演算法可以實現對任意多邊形的裁剪。(√)
第四章
1. 幾何變換是指改變幾何形狀和位置,非幾何變換是指改變圖形的顏色、線型等屬性。變換方法有對象變換(坐標系不動)和坐標變換(坐標系變化)兩種。
2. 坐標系可以分為以下幾種:世界坐標系(是對計算機圖形場景中所有圖形對象的空間定位和定義,是其他坐標系的參照)、模型坐標系(用於設計物體的局部坐標系)、用戶坐標系(為了方便交互繪圖操作,可以變換角度、方向)、設備坐標系(是繪制或輸出圖形的設備所用的坐標系,採用左手系統)。
3. 將用戶坐標系中需要進行觀察和處理的一個坐標區域稱為窗口,將窗口映射到顯示設備上的坐標區域稱為視區。從窗口到視區的變換,稱為規格化變換。(eg.4-1)
4. 所謂體素,是指可以用有限個尺寸參數定位和定形的體,如長方體、圓錐體。
5. 所謂齊次坐標表示,就是用n+1維向量表示n維的向量。
6. 二維點(x,y)的齊次坐標可以表示為:(hx hy h),其中h≠0。當h=1時稱為規范化的齊次坐標,它能保證點集表示的唯一性。
7. 旋轉變換公式的推導、對稱變換

第五章
1. 交互繪圖技術是一種處理用戶輸入圖形數據的技術,是設計交互繪圖系統的基礎。常見的交互繪圖技術有:定位技術、橡皮筋技術、拖曳技術、定值技術、拾取技術、網格與吸附技術。
2. 常用的橡皮筋技術有:橡皮筋直線、橡皮筋矩形、橡皮筋圓。
3. 拖曳技術是將形體在空間移動的過程動態地、連續地表示出來,直到用戶滿意。
4. 定值技術有2種:一種是鍵入數值,另一種是改變電位計阻值產生要求的數量,可以用模擬的方式實現電位計功能。
5. 拾取一個基本的對象可以通過:指定名稱法、特徵點發、外界矩陣法、分類法、直接法。

第六章
1. 點、線、面是形成三維圖形的基礎,三維變換是從點開始。
2. 三維圖形變換分類:三維圖形變換包括三維幾何變換和平面幾何變換,三維幾何變換包括基本幾何變換和復合變換;平面幾何變換包括平行投影和透視投影,平行投影包括正投影和軸測投影,透視投影包括一點透視、二點透視、三點透視。
3. 投影中心與投影面之間的距離是無限的投影叫做平行投影,它包括正投影和軸測投影。
4. 正投影形成的視圖包括:主視圖、俯視圖和左視圖。軸測投影形成的視圖為軸測圖。
5. 透視投影也稱為中心投影,其投影中心與投影面之間的距離是有限的。其特點是產生近大遠小的視覺效果
6. 對於透視投影,不平行於投影面的平行線的投影會匯聚到一個點,這個點稱為滅點。透視投影的滅點有無限多個,與坐標軸平行的平行線在投影面上形成的滅點稱為主滅點。主滅點最多有3個,其對應的透視投影分別稱為一點透視、二點透視、三點透視。

第七章
1. 型值點是曲面或曲線上的點,而控制點不一定在曲線曲面上,控制點的主要目的是用來控制曲線曲面的形狀。
2. 插值和逼近是曲線曲面設計中的兩種不同方法。插值—生成的曲線曲面經過每一個型值點,逼近—生成的曲線曲面靠近每一個控制點。
3. 曲線曲面的表示要求:唯一性、統一性、幾何不變性、幾何直觀、易於界定、易於光滑連接。
4. 曲線曲面有參數和非參數表示,但參數表示較好。非參數表示又分為顯式和隱式兩種。
5. 對於一個平面曲線,顯式表示的一般形式是:y=f(x)。一個x與一個y對應,因此顯式方程不能表示封閉或多值曲線。例不能用顯式方程表示一個圓。
6. 如果一個曲線方程表示為f(x,y)=0的形式,我們稱之為隱式表示。其優點是易於判斷函數f(x,y)是否大於、小於或等於零,即易於判斷是落在所表示曲線上還是在曲線的哪一側。
7. 參數連續與幾何連續的區別:參數連續性是傳統意義上的、嚴格的連續,而幾何連續性只需限定兩個曲線段在交點處的參數導數成比例,不必完全相等,是一種更直觀、易於交互控制的連續性。
8. 在曲線曲面造型中,一般只用到C1(1階參數連續)、C2(2階參數連續)、G1(1階幾何連續)、G2(2階幾何連續)。切矢量(一階導數)反映了曲線對參數t的變化速遞,曲率(二階導數)反映了曲線對參數t變化的加速度。
9. 通常C1連續必能保證G1的連續,但G1的連續並不能保證C1連續。
10. 對於三次Hermite曲線,用於描述曲線的可供選擇的條件有:端點坐標、切矢量和曲率。
11. 三次Hermite曲線特點:①可局部調整,因為每個曲線段僅依賴於端點約束;②基於Hermite樣條的變化形式有Cardinal樣條和Kochanek-Bartels樣條;③具有幾何不變性。
12. Bezier曲線的性質:①端點性質②端點切矢量③端點的曲率④對稱性⑤幾何不變性⑥凸包性⑦變差縮減性。
13. 一次Bezier曲線是連接起點P0和終點P1的直線段,二次Bezier曲線對應一條起點P0終點在P2處的拋物線。
14. B樣條曲線的性質:①局部性②連續性或可微性③幾何不變性④嚴格凸包性⑤近似性⑥變差縮減性。
15. NURRS曲線具有以下性質:①局部性②可微性③仿射不變性④嚴格保凸性⑤一般性⑥變差縮減性⑦端點性質。

第八章
1. 要把三維物體的信息顯示在二維顯示設備中,必須通過投影變換。由於投影變換失去了深度信息,往往會導致二義性,要消除二義性,就必須在繪制時消除實際不可見的線和面,稱作消除隱藏線和隱藏面,簡稱消隱。
2. 面消隱常用演算法有:深度緩沖區(Z-buffer)演算法和深度排序演算法(畫家演算法)。
3. 深度緩沖區演算法和深度排序演算法的區別:

『貳』 計算機圖形學 問題 中點圓演算法和掃描線演算法

寫個文檔解釋一下。

『叄』 請問中點bresenham演算法畫圓與bresenham演算法畫圓有區別嗎

Bresenham演算法畫圓:

Bresenham演算法用來畫直線非常方便,但上次也說了,Bresenham演算法也可以用來顯示圓和其他曲線,只需要把直線方程改成圓方程或者其他曲線的方程就行,具體的推理過程就不演示了,大體跟直線的差不多!但由推算的結果可以看出,用Bresenham演算法來畫圓的確是不大明智的做法,要計算的步驟太多,計算速度比專門的畫圓方法慢很多!並且在斜率越大的地方像素的間距就越大,當然我們可以在畫某個像素之前先判斷一下這一點跟前面一點的連線的斜率,然後在適當的時候交換x、y的坐標,但這樣計算量必將增加!

直接給出Bresenham畫圓的代碼:

#include<gl/glut.h>

#include<math.h>

#include<stdio.h>

voiddraw_pixel(intix,intiy)

{

glBegin(GL_POINTS);

glVertex2i(ix,iy);

glEnd();

}

//intinlineround(constfloata){returnint(a+0.5);}

voidBresenham(intx1,inty1,intr,doublea,doubleb,doublec)/*圓心在(x1,y1),半徑為r的圓*/

{

glColor3f(a,b,c);

intdx=r;//intdy=abs(yEnd-y1);

//intp=2*dy-dx;

//inttwoDy=2*dy,twoDyMinusDx=2*dy-2*dx;

intx,y,d1,d2;

/*if(x1>xEnd)

{

x=xEnd;y=yEnd;

xEnd=x1;

}

else

{

x=x1;

y=y1;

}

*/

x=x1;

y=y1+r;

draw_pixel(x1,y1);

draw_pixel(x,y);//起始點裝入幀緩存,起始點是圓的最上面一點,然後按順時針來畫

while(x<=x1+dx)

{

d1=y1+sqrt(pow(r,2)-pow(x-x1,2));/*lower*/

x++;

d2=2*(y1+sqrt(pow(r,2)-pow(x-x1,2)))-2*d1-1;/*lower-upper*/

if(1)

{

y=d1;

draw_pixel(x,y);

draw_pixel(x,2*y1-y);

draw_pixel(2*x1-x,y);

draw_pixel(2*x1-x,2*y1-y);

}

else

{

y++;

//p+=twoDyMinusDx;

draw_pixel(x,y);

}

}

}

voiddisplay()

{

glClear(GL_COLOR_BUFFER_BIT);

Bresenham(250,250,200,0.0,0.0,1.0);

Bresenham(300,250,150,1.0,0.0,0.0);

Bresenham(200,250,150,0.0,1.0,0.0);

//Bresenham(250,300,150,0.8,0.4,0.3);

//Bresenham(250,200,150);

glFlush();

}

voidmyinit()

{

glClearColor(0.8,1.0,1.0,1.0);

//glColor3f(0.0,0.0,1.0);

glPointSize(1.0);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluOrtho2D(0.0,500.0,0.0,500.0);

}

voidmain(intargc,char**argv)

{

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);

glutInitWindowSize(500,500);

glutInitWindowPosition(200.0,200.0);

glutCreateWindow("CG_test_Bresenham_Circleexample");

glutDisplayFunc(display);

myinit();

glutMainLoop();

}

以下為程序運行效果:

中點畫圓:

用光柵畫圓的不足在上次已經用實例表示的很明白了,上次畫的那個圓怎麼都不能算滿意,雖然可以通過修改演算法來得到改善,但本來計算步驟就已經很多了,交換坐標重新計算將會大大增加計算機的就是負擔,為此我們採用另一種更加常用的畫圓演算法——中點畫圓演算法,之所以叫做「中點」畫圓演算法是由於它不是像Bresenham演算法那樣所繪像素不是(xk+1,yk)就是(xk+1,yk+1),而是根據這兩個點的中點來判斷是(xk+1,yk)還是(xk+1,yk-1)更接近於圓!

對於給定的半徑r和圓心(x0,y0),我們先計算圓心在原點(0,0)的點,然後將其平移到圓心(x0,y0)處即可,跟Bresenham演算法一樣,我們也可以藉助圓的高度對稱性來減少計算機的計算步驟,在這里我們可以先計算出八分之一圓的像素點,然後根據對稱性繪出其他點。這樣可以大大加快畫圓的速度!

跟光柵化方法一樣,我們還是採用步進的方法來逐點描繪,但這里的決策參數計算方式跟Bresenham不大一樣,設決策參數為p,則:

P=x2+y2-r2

對於任一個點(x,y),可以根據p的符號來判斷點是在圓內還是圓外還是在圓上,這里不多說,假設我們在(xk,yk)處繪制了一個像素,下一步需要確定的是(xk+1,yk)還是(xk+1,yk-1)更接近於圓,在此代入這兩個點的中點來求出決策參數:

Pk=(xk+1)2+(yk-1/2)2-r2

如果Pk<0,則yk上的像素更接近於圓,否則就是yk-1更接近於圓

同理可以推出Pk+1=Pk+2(xk+1)+(yk+12-yk2)-(yk+1-yk)+1

給出一個示例,這個圓比用Bresenham畫出來的好看多了:

#include<glglut.h>

classscreenPt

{

private:

intx,y;

public:

screenPt(){x=y=0;}

voidsetCoords(GLintxCoordValue,GLintyCoordValue)

{

x=xCoordValue;

y=yCoordValue;

}

GLintgetx()const

{

returnx;

}

GLintgety()const

{

returny;

}

voidincrementx(){x++;}

voiddecrementy(){y--;}

};

voiddraw_pixel(intxCoord,intyCoord)

{

glBegin(GL_POINTS);

glVertex2i(xCoord,yCoord);

glEnd();

}

voidcircleMidpoint(GLintxc,GLintyc,GLintradius)

{

screenPtcircPt;

GLintp=1-radius;

circPt.setCoords(0,radius);

voidcirclePlotPoints(GLint,GLint,screenPt);

circlePlotPoints(xc,yc,circPt);

while(circPt.getx()<circPt.gety())

{

circPt.incrementx();

if(p<0)

p+=2*circPt.getx()+1;

else

{

circPt.decrementy();

p+=2*(circPt.getx()-circPt.gety())+1;

}

circlePlotPoints(xc,yc,circPt);

}

}

voidcirclePlotPoints(GLintxc,GLintyc,screenPtcircPt)//描繪八分圓各點

{

draw_pixel(xc+circPt.getx(),yc+circPt.gety());

draw_pixel(xc-circPt.getx(),yc+circPt.gety());

draw_pixel(xc+circPt.getx(),yc-circPt.gety());

draw_pixel(xc-circPt.getx(),yc-circPt.gety());

draw_pixel(xc+circPt.gety(),yc+circPt.getx());

draw_pixel(xc-circPt.gety(),yc+circPt.getx());

draw_pixel(xc+circPt.gety(),yc-circPt.getx());

draw_pixel(xc-circPt.gety(),yc-circPt.getx());

}

voiddisplay()

{

//screenPtPt;

glClear(GL_COLOR_BUFFER_BIT);

circleMidpoint(250,250,200);

glFlush();

}

voidmyinit()

{

glClearColor(0.8,1.0,1.0,1.0);

glColor3f(0.0,0.0,1.0);

glPointSize(1.0);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluOrtho2D(0.0,500.0,0.0,500.0);

}

voidmain(intargc,char**argv)

{

glutInit(&argc,argv);

glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);

glutInitWindowSize(500,500);

glutInitWindowPosition(200.0,200.0);

glutCreateWindow("CG_test_中點畫圓example");

glutDisplayFunc(display);

myinit();

glutMainLoop();

}

運行效果:

『肆』 怎樣用C語言畫圓

#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
char arg[50]={0};
arg[0]= '\ " ';
strcpy(arg+1,argv[0]);
int len=int(strlen(arg));
arg[len]= '\ " ';

HWND hWnd=FindWindow(NULL,arg); //找到程序運行窗口的句柄
HDC hDC=GetDC(hWnd);//通過窗口句柄得到該窗口的設備場境句柄
HPEN hPen,hOldPen; //畫筆
int i=0;

for(;i <500;++i)
SetPixel(hDC,10+i,10+i,0x0000ff);//用畫點的辦法畫一根線,最後一個參數是顏色(32位)

hPen=CreatePen(PS_SOLID,2,0x00ff00);//生成綠色畫筆
hOldPen=(HPEN)SelectObject(hDC,hPen);//把畫筆引入設備場境

MoveToEx(hDC,20,50,NULL); //設置畫線起點
LineTo(hDC,520,550); //畫到終點

Arc(hDC,100,100,300,300,350,500,350,500);//畫圓

SelectObject(hDC,hOldPen);
ReleaseDC(hWnd,hDC);

//下面是對比,表明它確實是控制台程序

printf( "hello console ");
system( "pause ");
return 0;

}

『伍』 直線和圓的顯示(在線等答案)

實驗2 圓與橢圓
給出圓心坐標(xc, yc)和半徑r,逐點畫出一個圓周的公式有下列兩種。
一 直角坐標法
直角坐標系的圓的方程為

由上式導出:

當x-xc從-r到r做加1遞增時,就可以求出對應的圓周點的y坐標。但是這樣求出的圓周上的點是不均勻的,| x-xc | 越大,對應生成圓周點之間的圓周距離也就越長。因此,所生成的圓不美觀。
二 中點畫圓法
如圖1所示,函數為F(x, y)=x2+y2-R2的構造圓,圓上的點為F(x, y)=0,圓外的點F(x, y)>0,圓內的點F(x, y)<0,構造判別式:
d=F(M)=F(xp+1, yp-0.5)=(xp+1)2+(yp-0.5)2
若d<0,則應取P1為下一像素,而且下一像素的判別式為
d=F(xp+2, yp-0.5)= (xp+2)2+(yp-0.5)2-R2=d+2xp+3
若d≥0,則應取P2為下一像素,而且下一像素的判別式為
d=F(xp+2, yp-1.5)= (xp+2)2+(yp-1.5)2-R2=d+2(xp- yp)+5
我們討論按順時針方向生成第二個八分圓,則第一個像素是(0, R),判別式d的初始值為
d0=F(1, R-0.5)=1.25-R
三 圓的Bresenham演算法
設圓的半徑為r,先考慮圓心在(0, 0),從x=0、y=r開始的順時針方向的1/8圓周的生成過程。在這種情況下,x每步增加1,從x=0開始,到x=y結束,即有xi+1 = xi + 1;相應的,yi+1則在兩種可能中選擇:yi+1=yi或者yi+1 = yi - 1。選擇的原則是考察精確值y是靠近yi還是靠近yi-1(見圖2),計算式為
y2= r2-(xi+1)2
d1 = yi2-y2 = yi2-r2+(xi+1)2
d2 = y2- (yi - 1)2 = r2-(xi+1)2-(yi - 1)2
令pi=d1-d2,並代入d1、d2,則有
pi = 2(xi+1)2 + yi2+ (yi - 1)2 -2r2 (1.6)
pi稱為誤差。如果pi<0,則yi+1=yi,否則yi+1=yi - 1。
pi的遞歸式為
pi+1 = pi + 4xi +6+2(yi2+1- yi2)-2(yi+1-yi) (1.7)
pi的初值由式(1.6)代入xi=0,yi=r,得
p1 = 3-2r (1.8)
根據上面的推導,圓周生成演算法思想如下:
(1)求誤差初值,p1=3-2r,i=1,畫點(0, r)。
(2)求下一個光柵位置,其中xi+1=xi+1,如果pi<0則yi+1=yi,否則yi+1=yi - 1。
(3)畫點(xi+1, yi+1)。
(4)計算下一個誤差,如果pi<0則pi+1=pi+4xi+6,否則pi+1=pi+4(xi - yi)+10。
(5)i=i+1,如果x=y則結束,否則返回步驟(2)。
程序設計步驟如下。
(1)創建應用程序框架,以上面建立的單文檔程序框架為基礎。
(2)編輯菜單資源。
在工作區的ResourceView標簽中,單擊Menu項左邊"+",然後雙擊其子項IDR_MAINFRAME,並根據表1中的定義添加編輯菜單資源。此時建好的菜單如圖3所示。
表1 菜單資源表
菜單標題 菜單項標題 標示符ID
圓 中點畫圓 ID_MIDPOINTCIRCLE
Bresenham畫圓 ID_BRESENHAMCIRCLE
(3)添加消息處理函數。
利用ClassWizard(建立類向導)為應用程序添加與菜單項相關的消息處理函數,ClassName欄中選擇CMyView,根據表2建立如下的消息映射函數,ClassWizard會自動完成有關的函數聲明。
表2 菜單項的消息處理函數
菜單項ID 消 息 消息處理函數
ID_MIDPOINTCIRCLE CONMMAN OnMidpointcircle
ID_BRESENHAMCIRCLE CONMMAN OnBresenhamcircle
(4)程序結構代碼,在CMyView.cpp文件中的相應位置添加如下代碼。

void CMyView::OnMidpointcircle() //中點演算法繪制圓,如圖4所示
{
// TODO: Add your command handler code here
CDC* pDC=GetDC();
int xc=300, yc=300, r=50, c=0;
int x,y;
float d;
x=0; y=r; d=1.25-r;
pDC->SetPixel ((xc+x),(yc+y),c);
pDC->SetPixel ((xc-x),(yc+y),c);
pDC->SetPixel ((xc+x),(yc-y),c);
pDC->SetPixel ((xc-x),(yc-y),c);
pDC->SetPixel ((xc+y),(yc+x),c);
pDC->SetPixel ((xc-y),(yc+x),c);
pDC->SetPixel ((xc+y),(yc-x),c);
pDC->SetPixel ((xc-y),(yc-x),c);
while(x<=y)
{ if(d<0) d+=2*x+3;
else { d+=2*(x-y)+5; y--;}
x++;
pDC->SetPixel ((xc+x),(yc+y),c);
pDC->SetPixel ((xc-x),(yc+y),c);
pDC->SetPixel ((xc+x),(yc-y),c);
pDC->SetPixel ((xc-x),(yc-y),c);
pDC->SetPixel ((xc+y),(yc+x),c);
pDC->SetPixel ((xc-y),(yc+x),c);
pDC->SetPixel ((xc+y),(yc-x),c);
pDC->SetPixel ((xc-y),(yc-x),c);
}
}
void CMyView::OnBresenhamcircle() //// Bresenham演算法繪制圓,如圖5所示
{
CDC* pDC=GetDC();
int xc=100, yc=100, radius=50, c=0;
int x=0,y=radius,p=3-2*radius;
while(x<y)
{
pDC->SetPixel(xc+x, yc+y, c);
pDC->SetPixel(xc-x, yc+y, c);
pDC->SetPixel(xc+x, yc-y, c);
pDC->SetPixel(xc-x, yc-y, c);
pDC->SetPixel(xc+y, yc+x, c);
pDC->SetPixel(xc-y, yc+x, c);
pDC->SetPixel(xc+y, yc-x, c);
pDC->SetPixel(xc-y, yc-x, c);
if (p<0)
p=p+4*x+6;
else
{
p=p+4*(x-y)+10;
y-=1;
}
x+=1;
}
if(x==y)
pDC->SetPixel(xc+x, yc+y, c);
pDC->SetPixel(xc-x, yc+y, c);
pDC->SetPixel(xc+x, yc-y, c);
pDC->SetPixel(xc-x, yc-y, c);
pDC->SetPixel(xc+y, yc+x, c);
pDC->SetPixel(xc-y, yc+x, c);
pDC->SetPixel(xc+y, yc-x, c);
pDC->SetPixel(xc-y, yc-x, c);
}

四 橢圓掃描轉換中點演算法
下面討論橢圓的掃描轉換中點演算法,設橢圓為中心在坐標原點的標准橢圓,其方 程為
F(x, y)=b2x2+a2y2-a2b2=0
(1)對於橢圓上的點,有F(x, y)=0;
(2)對於橢圓外的點,F(x, y)>0;
(3)對於橢圓內的點,F(x, y)<0。
以弧上斜率為-1的點作為分界將第一象限橢圓弧分為上下兩部分(如圖6所示)。
法向量:

而在下一個點,不等號改變方向,則說明橢圓弧從上部分轉入下部分。
與中點繪制圓演算法類似,一個像素確定後,在下面兩個候選像素點的中點計算一個判別式的值,再根據判別式符號確定離橢圓最近的點。先看橢圓弧的上半部分,具體演算法如下:
假設橫坐標為xp的像素中與橢圓最近點為(xp, yp),下一對候選像素的中點應為(xp+1,yp-0.5),判別式為

,表明中點在橢圓內,應取正右方像素點,判別式變為

若 ,表明中點在橢圓外,應取右下方像素點,判別式變為

判別式 的初始條件確定。橢圓弧起點為(0, b),第一個中點為(1,b - 0.5),對應判別式為

在掃描轉換橢圓的上半部分時,在每步迭代中需要比較法向量的兩個分量來確定核實從上部分轉到下半部分。在下半部分演算法有些不同,要從正上方和右下方兩個像素中選擇下一個像素。在從上半部分轉到下半部分時,還需要對下半部分的中點判別式進行初始化。即若上半部分所選擇的最後一個像素點為(xp, yp),則下半部分中點判別式應在(xp+0.5, yp-1)的點上計算。其在正下方與右下方的增量計算同上半部分。具體演算法的實現請參考下面的程序設計。
程序設計步驟如下。
(1)創建應用程序框架,以上面建立的單文檔程序框架為基礎。
(2)編輯菜單資源。
在工作區的ResourceView標簽中,單擊Menu項左邊"+",然後雙擊其子項IDR_MAINFRAME,並根據表3中的定義添加編輯菜單資源。此時建好的菜單如圖7所示。
表3 菜單資源表
菜單標題 菜單項標題 標示符ID
橢圓 中點畫橢圓 ID_MIDPOINTELLISPE

圖7 程序主菜單
(3)添加消息處理函數。
利用ClassWizard(建立類向導)為應用程序添加與菜單項相關的消息處理函數,ClassName欄中選擇CMyView,根據表4建立如下的消息映射函數,ClassWizard會自動完成有關的函數聲明。
表4 菜單項的消息處理函數
菜單項ID 消 息 消息處理函數
ID_MIDPOINTELLISPE CONMMAN OnMidpointellispe
(4)程序結構代碼如下:

void CMyView:: OnMidpointellispe () //中點演算法繪制橢圓,如圖8所示
{
CDC* pDC=GetDC();
int a=200,b=100,xc=300,yc=200,c=0;
int x,y;
double d1,d2;
x=0;y=b;
d1=b*b+a*a*(-b+0.25);
pDC->SetPixel(x+300,y+200,c);
pDC->SetPixel(-x+300,y+200,c);
pDC->SetPixel(x+300,-y+200,c);
pDC->SetPixel(-x+300,-y+200,c);
while(b*b*(x+1)<a*a*(y-0.5))
{
if(d1<0){
d1+=b*b*(2*x+3);
x++;}
else
{d1+=b*b*(2*x+3)+a*a*(-2*y+2);
x++;y--;
}
pDC->SetPixel(x+xc,y+yc,c);
pDC->SetPixel(-x+xc,y+yc,c);
pDC->SetPixel(x+xc,-y+yc,c);
pDC->SetPixel(-x+xc,-y+yc,c);
}
d2=sqrt(b*(x+0.5))+a*(y-1)-a*b;
while(y>0)
{
if(d2<0){
d2+=b*b*(2*x+2)+a*a*(-2*y+3);
x++;y--;}
else
{d2+=a*a*(-2*y+3);
y--;}
pDC->SetPixel(x+xc,y+yc,c);
pDC->SetPixel(-x+xc,y+yc,c);
pDC->SetPixel(x+xc,-y+yc,c);
pDC->SetPixel(-x+xc,-y+yc,c);
}
}

實驗一: 直 線
數學上,理想的直線是由無數個點構成的集合,沒有寬度。計算機繪制直線是在顯示器所給定的有限個像素組成的矩陣中,確定最佳逼近該直線的一組像素,並且按掃描線順序,對這些像素進行寫操作,實現顯示器繪制直線,即通常所說的直線的掃描轉換,或稱直線光柵化。
由於一圖形中可能包含成千上萬條直線,所以要求繪制直線的演算法應盡可能地快。本節介紹一個像素寬直線的常用演算法:數值微分法(DDA)、中點畫線法、Bresenham 演算法。
一. DDA(數值微分)演算法
DDA演算法原理:如圖1-1所示,已知過端點 的直線段 ;直線斜率為 ,從 的左端點 開始,向 右端點步進畫線,步長=1(個像素),計算相應的 坐標 ;取像素點 [ , round(y)] 作為當前點的坐標。計算 ,當 ,即當x每遞增1,y遞增k(即直線斜率)。
注意:上述分析的演算法僅適用於k1的情形。在這種情況下,x每增加1, y最多增加1。當 時,必須把x,y地位互換,y每增加1,x相應增加1/k(請參閱後面的Visual C++程序)。
二. 生成直線的中點畫線法
中點畫線法的基本原理如圖1-2所示。在畫直線段的過程中,當前像素點為P,下一個像素點有兩種選擇,點P1或P2。M為P1與P2中點,Q為理想直線與X=Xp+1垂線的交點。當M在Q的下方時,則P2應為下一個像素點;當M在Q的上方時,應取P1為下一點。
中點畫線法的實現:令直線段為L[ p0(x0,y0), p1(x1, y1)],其方程式F(x, y)=ax+by+c=0。
其中,a=y0–y1, b=x1–x0, c=x0y1–x1y0;點與L的關系如下。
在直線上,F(x, y)=0;
在直線上方,F(x, y)>0;
在直線下方,F(x, y)<0。
把M代入F(x, y),判斷F的符號,可知Q點在中點M的上方還是下方。為此構造判別式d=F(M)=F(xp+1, yp+0.5)=a(xp+1)+b(yp+0.5)+c。
當d < 0,L(Q點)在M上方,取P2為下一個像素。
當d > 0,L(Q點)在M下方,取P1為下一個像素。
當d=0,選P1或P2均可,取P1為下一個像素。
其中d是xp, yp的線性函數。
三. Bresenham演算法
Bresenham演算法是計算機圖形學領域使用最廣泛的直線掃描轉換演算法。由誤差項符號決定下一個像素取右邊點還是右上方點。
設直線從起點(x1, y1)到終點(x2, y2)。直線可表示為方程y = mx+b,其中b=y1–mx1, m = (y2–y1)/(x2–x1)=dy/dx;此處的討論直線方向限於第一象限,如圖1-3所示,當直線光柵化時,x每次都增加1個單元,設x像素為(xi,yi)。下一個像素的列坐標為xi+1,行坐標為yi或者遞增1為yi+1,由y與yi及yi+1的距離d1及d2的大小而定。計算公式為
y = m(xi + 1) + b (1.1)
d1 = y – yi (1.2)
d2=yi+1–y (1.3)
如果d1–d2>0,則yi+1=yi+1,否則yi+1=yi。
式(1.1)、(1.2)、(1.3)代入d1–d2,再用dx乘等式兩邊,並以Pi=(d1–d2),dx代入上述等式,得
Pi = 2xidy–2yidx+2dy+(2b–1)dx (1.4)
d1–d2是用以判斷符號的誤差。由於在第一象限,dx總大於0,所以Pi仍舊可以用做判斷符號的誤差。Pi+1為
Pi+1 = Pi+2dy–2(yi+1–yi)dx (1.5)
求誤差的初值P1,可將x1、y1和b代入式(1.4)中的xi、yi,而得到
P1 = 2dy–dx
綜述上面的推導,第一象限內的直線Bresenham演算法思想如下:
(1)畫點(x1, y1),dx=x2–x1,dy=y2–y1,計算誤差初值P1=2dy–dx,i=1。
(2)求直線的下一點位置xi+1 = xi + 1,如果Pi>0,則yi+1=yi+1,否則yi+1=yi。
(3)畫點(xi+1, yi+1)。
(4)求下一個誤差Pi+1,如果Pi>0,則Pi+1=Pi+2dy–2dx,否則Pi+1=Pi+2dy。
(5)i=i+1;如果i<dx+1則轉步驟(2);否則結束操作。
四. 程序設計
1 程序設計功能說明
編程實現上述演算法,本程序利用最基本的繪制元素(如點、直線等),繪制圖形。如圖1-4所示,為程序運行主界面,通過選擇菜單及下拉菜單的各功能項分別完成各種對應演算法的圖形繪制。

圖1-4 基本圖形生成的程序運行界面
2 創建工程名稱為「基本圖形的生成」單文檔應用程序框架
(1)啟動VC,選擇「文件」|「新建」菜單命令,並在彈出的新建對話框中單擊「工程」標簽。
(2)選擇MFC AppWizard(exe),在「工程名稱」編輯框中輸入 「基本圖形的生成」作為工程名稱,單擊「確定」按鈕,出現Step 1對話框。
(3)選擇「單個文檔」選項,單擊「下一個」按鈕,出現Step 2對話框。
(4)接受默認選項,單擊「下一個」按鈕,在出現的Step 3~Step 5對話框中,接受默認選項,單擊「下一個」按鈕。
(5)在Step 6對話框中單擊「完成」按鈕,即完成「基本圖形的生成」應用程序的所有選項,隨後出現工程信息對話框(記錄以上步驟各選項選擇情況),如圖1-5所示,單擊「確定」按鈕,完成應用程序框架的創建。

圖1-5 信息程序基本
3 編輯菜單資源
設計如圖1-4所示的菜單項。在工作區的ResourceView標簽中,單擊Menu項左邊「+」,然後雙擊其子項IDR_MAINFRAME,並根據表1-1中的定義編輯菜單資源。此時VC已自動建好程序框架,如圖1-5所示。
表1-1 菜單資源表
菜單標題 菜單項標題 標示符ID
直線 DDA演算法生成直線 ID_DDALINE
Bresenham演算法生成直線 ID_BRESENHAMLINE
中點演算法生成直線 ID_MIDPOINTLINE
4 添加消息處理函數
利用ClassWizard(建立類向導)為應用程序添加與菜單項相關的消息處理函數,ClassName欄中選擇CMyView,根據表1-2建立如下的消息映射函數,ClassWizard會自動完成有關的函數聲明。
表1-2 菜單項的消息處理函數
菜單項ID 消 息 消息處理函數
ID_DDALINE CONMMAN OnDdaline
ID_MIDPOINTLINE CONMMAN OnMidpointline
ID_BRESENHAMLINE CONMMAN OnBresenhamline
5 程序結構代碼,在CMyView.cpp文件中相應位置添加如下代碼:
// DDA演算法生成直線
void CMyView:: OnDdaline()
{
CDC* pDC=GetDC();//獲得設備指針
int xa=100,ya=300,xb=300,yb=200,c=RGB(255,0,0);//定義直線的兩端點,直線顏色
int x,y;
float dx, dy, k;
dx=(float)(xb-xa), dy=(float)(yb-ya);
k=dy/dx, y=ya;
if(abs(k)<1)
{
for (x=xa;x<=xb;x++)
{pDC->SetPixel (x,int(y+0.5),c);
y=y+k;}
}
if(abs(k)>=1)
{
for (y=ya;y<=yb;y++)
{pDC->SetPixel (int(x+0.5),y,c);
x=x+1/k;}
}
ReleaseDC(pDC);
}

說明:
(1)以上代碼理論上通過定義直線的兩端點,可得到任意端點之間的一直線,但由於一般屏幕坐標採用右手系坐標,屏幕上只有正的x, y值,屏幕坐標與窗口坐標之間轉換知識請參考第3章。
(2)注意上述程序考慮到當k1的情形x每增加1,y最多增加1;當k>1時,y每增加1,x相應增加1/k。在這個演算法中,y與k用浮點數表示,而且每一步都要對y進行四捨五入後取整。

//中點演算法生成直線
void CMyView::OnMidpointline()
{
CDC* pDC=GetDC();
int xa=300, ya=200, xb=450, yb=300,c=RGB(0,255,0);
int a, b, d1, d2, d, x, y;
a=ya-yb, b=xb-xa, d=2*a+b;
d1=2*a, d2=2* (a+b);
x=xa, y=ya;
pDC->SetPixel(x, y, c);
while (x<xb)
{ if (d<0) {x++, y++, d+=d2; }
else {x++, d+=d1;}
pDC->SetPixel(x, y, c);
}
ReleaseDC(pDC);
}

說明:
(1)其中d是xp, yp的線性函數。為了提高運算效率,程序中採用增量計算。具體演算法如下:若當前像素處於d>0情況,則取正右方像素P1(xp+1, yp),判斷下一個像素點的位置,應計算d1=F(xp+2, yp+0.5)=a(xp+2)+b(yp+0.5)=d+a;,其中增量為a。若d<0時,則取右上方像素P2(xp+1, yp+1)。再判斷下一像素,則要計算d2 = F(xp+2, yp+1.5)=a(xp+2)+b(yp+1.5) + c=d+a+b,增量為a+b。
(2) 畫線從(x0, y0)開始,d的初值d0=F(x0+1, y0+0.5)=F(x0, y0)+a+0.5b,因F(x0, y0)=0,則d0=a+0.5b。
(3)程序中只利用d的符號,d的增量都是整數,只是初始值包含小數,用2d代替d,使程序中僅包含整數的運算。

//Bresenham演算法生成直線
void CMyView::OnBresenhamline()
{
CDC* pDC=GetDC();
int x1=100, y1=200, x2=350, y2=100,c=RGB(0,0,255);
int i,s1,s2,interchange;
float x,y,deltax,deltay,f,temp;
x=x1;
y=y1;
deltax=abs(x2-x1);
deltay=abs(y2-y1);
if(x2-x1>=0) s1=1; else s1=-1;
if(y2-y1>=0) s2=1; else s2=-1;
if(deltay>deltax){
temp=deltax;
deltax=deltay;
deltay=temp;
interchange=1;
}
else interchange=0;
f=2*deltay-deltax;
pDC->SetPixel(x,y,c);
for(i=1;i<=deltax;i++){
if(f>=0){
if(interchange==1) x+=s1;
else y+=s2;
pDC->SetPixel(x,y,c);
f=f-2*deltax;
}
else{
if(interchange==1) y+=s2;
else x+=s1;
f=f+2*deltay;
}
}
}

說明:
(1)以上程序已經考慮到所有象限直線的生成。
(2)Bresenham演算法的優點如下:
① 不必計算直線的斜率,因此不做除法。
② 不用浮點數,只用整數。
③ 只做整數加減運算和乘2運算,而乘2運算可以用移位操作實現。
④ Bresenham演算法的運算速度很快。

『陸』 畫圓的常見演算法

畫圓的基本演算法有逐點比較和DDA積分法,
代碼示例 WinC下運行

#include "Conio.h"
#include "graphics.h"
#include "process.h"
#define Ni_circle 0
#define Shun_circle 1
#define closegr closegraph

void initgr();
void draw_Base_circle();
void draw_cabu_circle();
void close_graph();
void acrroods();
static float x0,y0;

void initgr(void) /* BGI初始化 */
{
int gd = DETECT, gm = 0; /* 和gd = VGA,gm = VGAHI是同樣效果 */
registerbgidriver(EGAVGA_driver);/* 注冊BGI驅動後可以不需要.BGI文件的支持運行 */
initgraph(&gd, &gm, "");
}

void acrroods() /*屏幕中心坐標 */
{
x0=getmaxx()/2;
y0=getmaxy()/2;
}

void draw_Base_circle() /*畫圓及寫參數*/
{
line(x0-200,y0,x0+200,y0); outtextxy(x0+220,y0,"Z");
line(x0,y0-180,x0,y0+180); outtextxy(x0+10,y0+180,"X");
outtextxy(x0-10,y0+10,"O");
circle(x0,y0,150);
textcolor(YELLOW);
directvideo=0;
gotoxy(46,2);cprintf("Circle start:X0 Y0 Z150");
gotoxy(46,3);cprintf("Circle end :X0 Y0 Z150");
gotoxy(46,4);cprintf("Units :Pixel");
gotoxy(46,5);cprintf("Circle now:");
}

void close_graph() /*關圖形系統*/
{
closegraph();
}

void draw_cabu_circle(int sstep,int Directory)/*關鍵的圓插補函數*/
{
int flag=0;
float Fm,Xm,Ym;
Xm=x0+150; Ym=y0;
moveto(Xm,Ym);
setcolor(RED);
while(1) /*分象限,順圓和逆圓討論*/
{
Fm=(Xm-x0)/(Xm-x0)+(Ym-y0)/(Ym-y0)-150/150;/*圓判斷公式*/
if(Fm>=0){
if(!Directory){ /*逆圓判斷*/
if(Xm>=x0&&Ym<=y0)
{
if(flag) break; /*if語句判斷象限,以下一樣*/
else Xm=Xm-sstep;
}
if(Xm<=x0&&Ym<=y0)
{
flag=1; Ym=Ym+sstep;
}
if(Xm<=x0&&Ym>=y0)
Xm=Xm+sstep;
if(Xm>=x0&&Ym>=y0)
Ym=Ym-sstep;
}
else { /*it is Directory's else*/
if(Xm>x0&&Ym<y0)
Ym=Ym+sstep;
if(Xm<=x0&&Ym<=y0)
Xm=Xm+sstep;
if(Xm<x0&&Ym>y0) {
flag=1; Ym=Ym-sstep;}
if(Xm>=x0&&Ym>=y0) {
if(flag) break;
Xm=Xm-sstep;}
}
}
else{ /*it is Fm's else*/
if(!Directory) {
if(Xm>x0&&Ym<y0)
{
if(flag) break;
else Ym=Ym-sstep;
}
if(Xm<=x0&&Ym<=y0)
{
flag=1; Xm=Xm-sstep;
}
if(Xm<=x0&&Ym>=y0)
Ym=Ym+sstep;
if(Xm>=x0&&Ym>=y0)
Xm=Xm+sstep;
}
else{
if(Xm>x0&&Ym<y0)
Xm=Xm+sstep;
if(Xm<=x0&&Ym<=y0)
Ym=Ym-sstep;
if(Xm<=x0&&Ym>=y0){
flag=1; Xm=Xm-sstep;}
if(Xm>=x0&&Ym>=y0) {
if(flag) break;
else Ym=Ym+sstep;}
}
}
lineto(Xm,Ym);
gotoxy(58,5); printf("X%3.0f Y0 Z%3.0f ",Ym-y0,Xm-x0);
delay(800);
}
}

void circle_demo(int Directory) /*控制圓插補兩次*/
{
int i=0,sstep;
initgr(); /* BGI初始化 */
sleep(2);
acrroods(&x0,&y0);
for(i=0;i<2;i++)
{
draw_Base_circle(150);
if(i==0){
sstep=6;
draw_cabu_circle(sstep,Directory);}
else{
sstep=1;
draw_cabu_circle(sstep,Directory);}
getch();
cleardevice();
setcolor(WHITE);
}
}

/* 圓插補部分的函數區結束*/

int main(void)
{
int choice=0;
initgr(); /* BGI初始化 */

while(choice!=4)
{
setfillstyle(1,RED);
bar(200,30,400,80);
setcolor(GREEN);
settextstyle(3,0,10);
outtextxy(220,50,"DEMO PROGRAM BY P.Y.F");
setcolor(WHITE);
settextstyle(0,0,1);
outtextxy(200,140,"2. Shun_Circle demo.");
outtextxy(200,160,"3. Ni_Circle demo.");
outtextxy(200,180,"4. Quit the program.");
outtextxy(160,200,"Please enter your choice:"); gotoxy(46,13);
scanf("%d",&choice);

switch(choice)
{
case 2: circle_demo(Ni_circle);break;
case 3: circle_demo(Shun_circle);break;
case 4: break;
default: printf("\nChoice wrong,try again!");
}
}

getch(); /* 暫停一下,看看前面繪圖代碼的運行結果 */
closegr(); /* 恢復TEXT屏幕模式 */
return 0;
}

具體看看《計算機圖形學》。

『柒』 CAD怎麼在一條直線中間加個圓 說的簡明些

對象捕捉選項里把中點勾上
然後以直線的中間為圓心,畫一個圓

『捌』 圖形學中的中點畫線法與Bresenham演算法畫線的區別

個人認為最關鍵的區別就是那個決策參數的計算方式!
在Bresenham演算法中,假設我們在(x0,y0)處畫了一個點,那我們就要決定下一個點是在(x0+1,y0)還是在(x0+1,y0+1)處畫,這兩個點一般都不在直線上,我們要計算這兩個點離直線有多遠,分別設兩個點離直線的距離為p1、p2,然後決策參數就是p=p2-p1,再根據p的符號來判斷選擇哪個點
至於中點法,我沒有用它來畫過直線,只用來畫過圓(自我感覺畫圓用這個演算法比Bresenham演算法要好很多),但原理應該差不多!
在中點演算法中,決策參數的就是方式就是圓的方程(換成直線就是直線的方程了),比如要畫x^2+y^2=r^2的圓,那決策參數p=x^2+y^2-r^2,然後就不是代入上面找到的兩個點直接代進去,而是代這兩個點的中點進去,求出p的值,根據p的符號來判斷那個中點是在圓上、圓內還是圓外,再進一步決定選擇繪哪個點!
具體的計算過程沒辦法在這里完整演示,但個人認為不同之處還是在於決策參數的選擇與計算

『玖』 lisp,一直線中點繪制一個圓,怎麼實現的

(defunc:ttt(/#os1baqdzdjl1jdzxdr1r2)
(setvar"cmdecho"0)
(setvar"blipmode"0)
(setq#os1(getvar"osmode"));;取得捕捉設置
(if(nullvlax-mp-object)(vl-load-com));;載入vlax擴展函數
(setqb(entsel" 請選擇直線"))
(if(/=bnil);;如果有選擇;如果沒有選擇就結束
(progn;;繼續分析
(setqb(entget(carb)));;取得屬性列表
(setqa(cdr(assoc0b)));;取得圖元名
(if(=a"LINE");;如果是直線;如果不是直線就結束
(progn;;繼續分析
(setqqd(cdr(assoc10b)));;取得起點;要加cdr才可以得到點
(setqzd(cdr(assoc11b)));;取得端點
(setqjl1(distanceqdzd));;取得長度
(setqjl1(/jl12));;取得長度一半;如果後面用不到這個jl1可以使用jl1
(setqjd(angleqdzd));;取得角度
(setqzxd(polarqdjdjl1));;取得中點
(setqr1100);;設置半徑默認為100
(setqr2(getint(strcat" 請輸入半徑:<"(rtosr120)">")));;輸入半徑
(if(=r2nil)(setqr2r1));;如果沒有輸入就默認
(setvar"osmode"0);;關閉捕捉;如不關閉可能繪圖不正確
(command"circle"zxdr2);;繪制圓
(setvar"osmode"#os1);;還原捕捉設置
)
)
)
)
(princ)
)

你仔細核對有那裡不同

(defunc:ttt(/#os1bqdzdjd)
(setvar"cmdecho"0)
(setvar"blipmode"0)
(setq#os1(getvar"osmode"));;取得捕捉設置
(if(nullvlax-mp-object)(vl-load-com));;載入vlax擴展函數
(setqb(entsel" 請選擇直線"))
(if(/=bnil);;如果有選擇
(progn;;繼續分析
(setqb(entget(carb)));;取得屬性列表
(setqqd(cdr(assoc0b)));;取得圖元名
(if(=qd"LINE");;如果是直線
(progn;;繼續分析
(setqqd(cdr(assoc10b)));;取得起點
(setqzd(cdr(assoc11b)));;取得端點
(setqjd(angleqdzd));;取得角度
(setqzd(distanceqdzd));;取得長度
(setqzd(/zd2));;取得長度一半;如果後面用不到這個zd可以使用zd
(setqzd(polarqdjdzd));;取得中點
(setqqd100);;設置為100
(setqjd(getint(strcat" 請輸入半徑:<"(rtosqd20)">")))
(if(=jdnil)(setqjdqd));;如果沒有輸入就默認
(setvar"osmode"0);;關閉捕捉;如不關閉可能繪圖不正確
(command"circle"zdjd)
(setvar"osmode"#os1)
)
)
)
)
(princ)
);;這個程序減少了很多參數因為後面的不使用了所有可以重復使用
閱讀全文

與中點直線畫圓演算法相關的資料

熱點內容
賣手錶的app哪裡可以賣 瀏覽:51
放管伺服器怎麼辦理 瀏覽:627
手機號碼如何加密 瀏覽:424
沈陽程序員培訓學校 瀏覽:538
一般伺服器如何配置 瀏覽:895
圖片怎樣加密發郵件 瀏覽:619
萬虹電腦文件夾密碼忘記了怎麼辦 瀏覽:631
rc108單片機 瀏覽:867
戰雷如何改變伺服器 瀏覽:674
mactelnet命令 瀏覽:51
壓縮袋壓縮了拿出來 瀏覽:401
安卓手機相機怎麼設置許可權 瀏覽:121
美女程序員轉行做主播 瀏覽:671
辦理解壓房產 瀏覽:575
道路工程概論pdf 瀏覽:390
超棒數學速演算法大全 瀏覽:938
小米易語言登錄源碼 瀏覽:32
磚牆內加密鋼筋 瀏覽:994
鄉關何處pdf 瀏覽:85
小豬領贊小程序源碼 瀏覽:336