【EasyX】快速入門——靜態圖形篇

1.基本說明

EasyX 是針對 C++ 的圖形庫,可以幫助 C/C++ 初學者快速上手圖形和游戲編程。

比如,可以基于 EasyX 圖形庫很快的用幾何圖形畫一個房子,或者一輛移動的小車,可以編寫俄羅斯方塊、貪吃蛇、黑白棋等小游戲,可以練習圖形學的各種算法,等等。

許多人學編程都是從 C 語言入門的,而現狀是:

  1. 有些學校以 Turbo C 為環境學習 C 語言,只是 Turbo C 實在太老了,復制粘貼都很不方便。
  2. 有些學校直接拿 VC 來講 C 語言,因為 VC 的編輯和調試環境都很優秀,并且 VC 有適合教學的免費版本。可惜在 VC 里面只能做一些文字性的練習題,想畫條直線或一個圓都很難,例如需要注冊窗口類、建消息循環等等,初學者會受嚴重打擊的。初學編程想要繪圖就得用 TC,很是無奈。
  3. 還有計算機圖形學,這門課程的重點是繪圖算法,而不是 Windows 編程。所以,許多老師不得不用 TC 教學,因為 Windows 繪圖太復雜了,會偏離教學的重點。新的圖形學的書有不少是用的 OpenGL,可是門檻依然很高。

于是就有了這個 EasyX 庫。如果您剛開始學 C 語言,或者您是一位教 C 語言的老師,再或者您在教計算機圖形學,那么這個庫一定會讓您興奮的。

2.系統支持

操作系統:Windows XP(sp3) 及以上操作系統。
編譯環境:Visual C++ 6.0,Visual Studio 2008 至 Visual Studio 2022 (x86 & x64)。

3.安裝——EasyX Graphics Library for C++

請下載最新版 EasyX 安裝程序,直接運行,并跟隨提示安裝即可。

安裝程序會自動檢測您已經安裝的 VC 版本,并根據您的選擇將對應的 .h 和 .lib 文件安裝至 VC 的 include 和 lib 文件夾內。安裝程序不會修改注冊表或者您本機的其它任何文件。

4.如何學習easyx?

其實學習easyx的最好的方法就是看它的文檔——EasyX 文檔 - 基本說明?

5.第一個程序

首先我們要知道easyx是使用C++語言的,所以我們創建的源文件應該是.cpp后綴的

同樣我們使用的不是<stdio.h>的頭文件了,我們使用的是<easyx.h>的文件,就像下面這樣子

6.easyx快速入門之路(有點漫長,請耐心走完哦)

6.1.initgraph函數

這個函數用于初始化繪圖窗口。

?

6.2.closegraph函數?

創建了窗體,我們肯定要關閉窗體

這個函數用于關閉繪圖窗口。

我們直接上例子

#include<easyx.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體closegraph();return 0;
}

運行一下,我們發現窗體一閃而過,這是因為創建繪圖窗體之后又立馬關閉了,那怎么辦呢?

我們可以使用getchar()暫時阻塞程序,等待用戶按鍵后再關閉

getchar在<stdio.h>里面

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體getchar();closegraph();return 0;
}

?

?我們可以看到一個黑色的繪圖窗體,按回車鍵就關閉了窗體

6.3circle函數

該函數使用當前畫線樣式繪制無填充的圓。

我們看個例子?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體circle(0, 0, 300);getchar();closegraph();return 0;
}

我丟,這個圓心怎么在窗體的最左上方?這是因為easyx的坐標系統的原因

6.4easyx的坐標系統

我們先看看官網怎么說

?再看看圖

?我們之前畫的圓形的圓心是(0,0),是邏輯坐標的默認值,所以圓心自然在左上方了

邏輯坐標的原點是可以移動的,我們可以修改邏輯坐標的原點移動到窗體的中間

6.5setorigin函數

我們舉個例子

學會了這個,我們再去修改那個繪制圓的函數

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點circle(0, 0, 300);getchar();closegraph();return 0;
}

?我們看到啊,終于圓心位于正中央了!!

6.7setaspectratio函數

我們雖然把邏輯坐標的圓心改到了最中間的位置,但是y軸的方向和我們熟悉的軸線完全不一樣。因此我們有必要去修改一下y軸的方向

?我們再完善一下上面那個代碼

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向circle(0, 0, 300);getchar();closegraph();return 0;
}

?6.8putpixel函數

這個函數用于畫點。

我們先了解下面這些顏色,更多的顏色表示我們不急?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向putpixel(0, 0, RED);putpixel(200, 200, YELLOW);putpixel(200, -200, CYAN);putpixel(-200, -200, GREEN);putpixel(-200, 200, WHITE);getchar();closegraph();return 0;
}

WHAT?點呢?不要慌張,因為一個點是一個像素大小,我們很難看見它們?

我們讓效果更明顯一點,我們隨機生成100個點,x,y的坐標取值范圍如下

?我們讓效果更明顯一點,我們隨機生成100個點

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向int x, y;for (int i = 0; i < 1000; ++i){x = rand() % (800 + 1) - 400;y = rand() % (600 + 1) - 300;putpixel(x, y, WHITE);}getchar();closegraph();return 0;
}

這個效果就非常明顯了哈!?

6.9line函數

這個函數用于畫直線。

舉個例子?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向line(-200, 200, 200, -200);line(-200, -200, 200, 200);getchar();closegraph();return 0;
}

?6.10畫多個圓

我們學會了用circle來畫圓形,那我們加大一點難度

代碼:?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向for (int r = 10; r <= 300; r += 10){circle(0, 0, r);}getchar();closegraph();return 0;
}

?6.11rectangle函數

這個函數用于畫無填充的矩形。

示例?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向rectangle(-200, 100, 200, -100);getchar();closegraph();return 0;
}

?看效果

?6.12ellipse函數

這個函數用于畫無填充的橢圓。

舉例:?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向ellipse(-200, 100, 200, -100);getchar();closegraph();return 0;
}

6.12roundrect函數?

這個函數用于畫無填充的圓角矩形。

圓角矩形的樣子如下?

?

我們舉例

代碼

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向roundrect(-200, 100, 200, -100,200,100);getchar();closegraph();return 0;
}

6.13pie函數

?繪制扇形

?注意是順時針旋轉單位為弧度

舉例

代碼

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向pie(-200, 100, 200, -100,0,PI/4);getchar();closegraph();return 0;
}

6.14arc函數?

繪制圓弧

舉例

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向arc(-200, 100, 200, -100,0,PI/4);getchar();closegraph();return 0;
}

?7.繪制多邊形

基本的函數我們掌握了,我們就玩點進階的吧!

7.1繪制三角形

我們舉個例子

代碼

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向line(0, 200, 200, -200);line(200, -200, -200, -200);line(-200, -200, 0, 200);getchar();closegraph();return 0;
}

7.2polygon函數?

如果我們繪制多邊形都要像上面那樣子,就會很復雜,不過好在easyx有一個函數來幫我們繪制多邊形,那就是polygon函數

我們看看這個POINT是個什么東西?

?舉例

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向// 方法 1POINT pts[] = { {50, 200}, {200, 200}, {200, 50} };polygon(pts, 3);// 方法 2int pts2[] = { 0, 0,  100, 200,  200, 50 };polygon((POINT*)pts2, 3);getchar();closegraph();return 0;
}

?

7.3繪制矩形

?我們可以使用polygon函數來繪制矩形

假如我們要繪制下面這樣一個圖像

代碼?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向// 方法 1POINT pts[] = { {-200,100}, {200, 100}, {200, -100},{-200,-100 } };polygon(pts, 4);getchar();closegraph();return 0;
}

7.4繪制梯形?

代碼:

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向// 方法 1POINT pts[] = { {-100,100}, {100, 100}, {200, -100},{-200,-100 } };polygon(pts, 4);getchar();closegraph();return 0;
}

?7.5繪制五邊形

繪制五邊形比前面繪制四邊形多了一個棘手的問題,就是我們很難確定五個點的坐標?

那我們可以使用三角函數來得到坐標

我們看看P1和P2是怎么求的

這個時候,敏銳的同學就會發現 我們可以通過一個循環來得到五個點的坐標,起始角度是90度,每次循環增加360/5=72度,就可以得到五個點的坐標

注意:sin和cos用的是弧度制,所以代碼要用弧度制來

?代碼:

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向double theta = PI / 2;//起始角度double delta = 2 * PI / 5;//每次循環增加的角度int r = 200;POINT points[5];for (int i = 0; i < 5; ++i){points[i].x = cos(theta + i * delta) * r;points[i].y = sin(theta + i * delta) * r;}polygon(points, 5);getchar();closegraph();return 0;
}

7.6繪制不規則的圖形?

我們可以使用polygon函數來繪制不規則圖形

?例如我們可以繪制像下面這樣一個多邊形

代碼

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向POINT points[8] = { {-400,0},{-200,200},{0,50},{200,200},{400,0},{200,150},{0,0},{-200,150} };polygon(points, 8);getchar();closegraph();return 0;
}

呢我們能不能畫一個W呢?

答案是polygon函數不能,因為polygon函數會按順序依次連接各個點最后會繪制一條P1到P5的線

7.7polyline函數

既然我們不能使用polygon來描繪出不封閉的圖形W,我們可以使用polyline函數來繪制,這個函數和polygon的唯一區別就是它不會自動連接首尾兩個點,

我們接著畫上面那個W圖形

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);//翻轉y軸的方向POINT points[5] = { {-400,200},{-200,-200},{0,100},{200,-200},{400,200} };polyline(points, 5);getchar();closegraph();return 0;
}

8.形狀的樣式?

前面我們學習了一系列圖形的函數,但是我們發現,它們都是白色的單一線條,那我們如何讓這些圖形豐富起來呢?

8.1僅描邊圖形樣式

我們先復習一下畫圓的代碼

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點circle(0, 0, 300);getchar();closegraph();return 0;
}

我們可以發現它是僅由一條白線組成,而且圓的內部沒有填充任何顏色

我們將圖形邊緣的線條稱為圖形的描邊,描邊的顏色默認為白色,包括我們之前學習的所有繪制圖形的函數,都是如此。

8.2setlinecolor函數?

我們不想讓描邊的顏色是白色,我們可以使用setlinecolor函數來設置描邊的顏色

我們來使用一下

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setlinecolor(RED);circle(0, 0, 300);getchar();closegraph();return 0;
}

?很好,描邊變紅色了。

8.3setlinestyle函數

我們覺得感覺樣式也太單調了,那我們可以使用setlinestyle函數來改變描邊的樣式

這個函數用于設置當前設備畫線樣式

我們現在先重點關注前兩個參數

先看第一個參數 ,參數 style 指定了畫線樣式,該樣式由直線樣式、端點樣式、連接樣式三類組成。可以是其中一類或多類的組合。同一類型中只能指定一個樣式。

8.3.1線形樣式

?掩碼宏表示對應樣式組所占用的所有位。例如,對于一個已經混合了多種樣式的 style 變量,如果希望僅將直線樣式修改為點劃線,可以這么做:

style = (style & ~PS_STYLE_MASK) | PS_DASHDOT;

我們舉個例子

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setlinestyle(PS_SOLID);circle(0, 0, 50);setlinestyle(PS_DASH);circle(0, 0, 100);setlinestyle(PS_DOT);circle(0, 0, 150);setlinestyle(PS_DASHDOT);circle(0, 0, 200);setlinestyle(PS_DASHDOTDOT);circle(0, 0, 250);setlinestyle(PS_NULL);circle(0, 0, 300);getchar();closegraph();return 0;
}

我丟,這誰看得清楚啊

這個時候,我們就可以使用第二個參數來設置線條的粗細

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setlinestyle(PS_SOLID,4);circle(0, 0, 50);setlinestyle(PS_DASH,4);circle(0, 0, 100);setlinestyle(PS_DOT,4);circle(0, 0, 150);setlinestyle(PS_DASHDOT,4);circle(0, 0, 200);setlinestyle(PS_DASHDOTDOT,4);circle(0, 0, 250);setlinestyle(PS_NULL,4);circle(0, 0, 300);getchar();closegraph();return 0;
}

?怎么樣?夠清晰了吧!

8.3.2端點樣式

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);setlinestyle(PS_ENDCAP_ROUND, 16);line(-300, 200, 300, 200);setlinestyle(PS_ENDCAP_SQUARE, 16);line(-300, 150, 300, 150);setlinestyle(PS_ENDCAP_SQUARE, 16);line(-300, 100, 300, 100);getchar();closegraph();return 0;
}

?8.3.3連接樣式

?代碼

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);setlinestyle(PS_JOIN_BEVEL,64);POINT point1[3] = { {-150,100},{0,200},{150,100} };polyline(point1, 3);setlinestyle(PS_JOIN_MITER,64);POINT point2[3] = { {-150,0},{0,100},{150,0} };polyline(point2, 3);setlinestyle(PS_JOIN_ROUND,64);POINT point3[3] = { {-150,-100},{0,0},{150,-100} };polyline(point3, 3);getchar();closegraph();return 0;
}

?8.4.僅填充圖形樣式

在之前學習的封閉圖形的時候,我們發現里面都是空的,那么我們可以來進行填充

這些函數和使用描邊繪制圖形函數基本一模一樣,唯一的區別就是在函數名前加solid

例如我們要繪制有填充的圖形樣式,就要使用solidcircle函數

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);solidcircle(0, 0, 100);getchar();closegraph();return 0;
}

我們發現這個默認填充顏色是白色,那我們如何修改這個填充顏色呢?

8.4.1setfillcolor函數?

這個函數是來設置填充顏色的

我們可以對上面的代碼進行改進

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);setfillcolor(YELLOW);solidcircle(0, 0, 100);getchar();closegraph();return 0;
}

8.5描邊加填充圖形樣式?

前面我們學習了僅描邊或者僅填充的樣式,那如果我既想讓它有描邊樣式,又有填充樣式,我們該怎么辦呢

很簡單,僅在函數名前加fill

代碼?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);setlinecolor(RED);setlinestyle(PS_DASH, 12);setfillcolor(YELLOW);fillcircle(0, 0, 200);getchar();closegraph();return 0;
}

?8.6設置背景色——setbkcolor

例如,我們想把我們的背景設置為白色

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);setbkcolor(WHITE);getchar();closegraph();return 0;
}

什么,怎么還是黑色的?

我們看看文檔

我靠,原來如此

我們改進一下

8.7cleardevice函數

使用這個函數,代表之前繪制的一切東西都會被清空?

有了這個我們就能對上面的進行改進了

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);setbkcolor(WHITE);cleardevice();getchar();closegraph();return 0;
}

我靠,成功了!!?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);setbkcolor(WHITE);cleardevice();setfillcolor(BLUE);solidcircle(0, 0, 300);getchar();closegraph();return 0;
}

9.顏色模型?

在此之前,我們用的顏色都是easyx已經定義好的顏色

但是這些顏色還是具有很多局限性的,無法表示更多豐富多彩的顏色樣式

9.1RGB顏色模型

不知道大家有沒有近距離的觀察過屏幕,我們就會發現屏幕居然是由很多紅點,綠點,藍點組成的,其他顏色均是由這三種顏色混合而成的。其實啊,這個是因為顯示器使用了人眼的三原色原理

我們將每種原色從弱到強分為256等分?

這個時候我們將不同比例的原色進行混合,就可以形成各種各樣的顏色

此外,顏色值也可以使用三原色份數的十六進制數進行組合表示

?那么,我們在代碼中怎么使用RGB顏色模型呢?

在easyx中,提供了一個名為RGB的函數

有人就好奇了,這個BYTE是個啥?我們看

又有人好奇了這個COLORREF是個啥?

很好!!接下來我們就來使用這個函數

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setbkcolor(RGB(134, 172, 242));cleardevice();getchar();closegraph();return 0;
}

成功啦!!哈哈?

9.2.HSV顏色模型

我們看下面這個

我們把三原色放在圓形的三等分點處,然后按與三原色的距離來分配不同顏色的比例,就能得到像下面這樣一個色環

我們發現,每一個角度都代表一種顏色,這個就叫色相,此外,HSV顏色模型還提供了兩個參數,用于控制顏色的鮮艷程度和明暗程度,它們分別為飽和度和明度。

例如,我們選取色相為240度,就是藍色,選取不同飽和度,明度,我們得到的顏色也不同

?飽和度下降,越靠近白色,明度下降,越靠近黑色,明度有時候也叫亮度,所以HSV和HSB是一個東西

但是顯示屏是使用三原色原理制作的,HSV模型無法使用于顯示屏

但是我們可以使用HSV模式選好顏色,再將其轉換為RGB模式,就可以顯示在屏幕上

9.2.1.HSVtoRGB函數

該函數將HSV顏色轉換為RGB顏色

我們可以使用在線拾色器選取一個顏色,然后將其轉換為RGB顏色

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setbkcolor(HSVtoRGB(219,0.45,0.95));cleardevice();getchar();closegraph();return 0;
}

9.3.繪制彩虹窗體?

我們怎么做才能得到彩虹色的背景呢?

其實很簡單,我們只需要環繞色環轉一圈即可

也就是色相從0開始到360度逐漸遞增變化,明度飽和度選100%就可以了

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體float dH = 360.0 / 600.0;float h = 0;for (int y = 0; y < 600; ++y){setlinecolor(HSVtoRGB(h, 1, 1));line(0, y, 800, y);h += dH;}getchar();closegraph();return 0;
}

9.4.繪制藍天,彩虹?

我們想畫下面這樣子的圖

那我們要怎么做呢?

我們線畫漸變色的藍天吧!很簡單,把圖拆分為600條線(因為寬是600像素)

?看代碼

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體float s = 0.76;float ds = s/600;for (int y = 0; y < 600; ++y){setlinecolor(HSVtoRGB(216, s, 0.95));line(0, y, 800, y);s -= ds;}getchar();closegraph();return 0;
}

我丟,這么美?,得抓緊畫彩虹了,彩虹很簡單

我們看代碼?

#include<easyx.h>
#include<stdio.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體float s = 0.76;float ds = s/600;for (int y = 0; y < 600; ++y){setlinecolor(HSVtoRGB(216, s, 0.95));line(0, y, 800, y);s -= ds;}float h = 0;float dh = 360.0 / 100.0;for (int r = 300; r >= 200; --r){setlinecolor(HSVtoRGB(h, 1, 1));circle(400, 600, r);h += dh;}getchar();closegraph();return 0;
}

10.剪切區域?

我們希望能用圓形畫出像下面這樣一朵花

很明顯,這是許多個等半徑的圓形組成的,圓心都位于內部圓形的六等分處,我們就可以使用三角函數來得到圓心的坐標

我們直接上代碼?

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);//設置邏輯坐標的原點setaspectratio(1, -1);setbkcolor(WHITE);cleardevice();setlinecolor(BLACK);setlinestyle(PS_SOLID, 10);int r = 150;circle(0, 0, r);for (int i = 0; i < 6; ++i){int x = cos(i * (2 * PI / 6)) * r;int y=sin(i * (2 * PI / 6)) * r;circle(x,y,r);}getchar();closegraph();return 0;
}

這不就是小case嗎!!!哈哈哈

現在我們有新需求,我們只要中間這個圓形,其他的不要

那我們怎么做呢?

這就需要學習新知識了——剪切區域

10.1剪切區域

我們在繪制前設置剪切區域,繪制在剪切區域的圖形將被保留,繪制在剪切區域的圖形將被拋棄

注意:必須先建立剪切區域,再調用繪圖函數

回到上面那個問題,我們可以先建立一個剪切區域

這樣子白色部分的將被保留,其他的將被刪除

10.2.創建區域

我們怎么創建剪切區域呢?

easyx并沒有直接提供創建區域的函數,因此我們需要借助Windows GDI

我們一個一個來好好看看

?

我們發現,這些函數和它們對應的圖形繪制函數的參數形式一模一樣 ,實際上,它們分別和對應的繪制函數的用法也是一模一樣的

注意:剪切區域是以物理坐標為坐標系的

由于沒有直接繪制圓形的函數,我們可以使用繪制橢圓的

10.3設置剪切區域——setcliprgn函數

小兄弟,光創建了區域還不行,我們還得把它設置成剪切區域才行!!!

而setcliprgn剛好是用來干這個活的

很好,萬事具備,只欠東風,我們開寫

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);setaspectratio(1, -1);setbkcolor(WHITE);cleardevice();setlinecolor(BLACK);setlinestyle(PS_SOLID, 10);int r = 150;HRGN rgn = CreateEllipticRgn(250, 150, 550, 450);//創建區域setcliprgn(rgn);//將創建的區域設置為剪切區域circle(0, 0, r);for (int i = 0; i < 6; ++i){int x = cos(i * (2 * PI / 6)) * r;int y=sin(i * (2 * PI / 6)) * r;circle(x,y,r);}setcliprgn(NULL);//將剪切區域設為空DeleteObject(rgn);//銷毀區域getchar();closegraph();return 0;
}

注意繪圖完成后,要將剪切區域設為空,并且要刪除創建的區域

我靠,就這?太簡單了吧!!別急,更厲害的還在后面,加油吧,少年

10.4.CombineRgn函數

區域之間可以進行集合運算并組合 ,我們可以使用CombineRgn函數來組合區域,這個函數也不是easyx自帶的,所以用的也是物理坐標

這個函數是讓源區域1和源區域2按照某種組合模式(第四個參數)進行組合得到新的剪切區域

組合模式如下

第一個參數是沒有什么太大的意義的,但是它必須是一個存在的區域,它是用來承接組合后的區域的

接下來我們就舉幾個例子來看看怎么使用組合區域

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);setaspectratio(1, -1);setbkcolor(WHITE);cleardevice();setlinecolor(BLACK);setlinestyle(PS_SOLID, 10);int r = 150;HRGN rgn1 = CreateEllipticRgn(250, 250, 550, 550);//創建區域HRGN rgn2 = CreateEllipticRgn(250, 100, 550, 400);//創建區域HRGN rgn = CreateEllipticRgn(0,0,0,0);//創建區域CombineRgn(rgn, rgn1, rgn2, RGN_AND);setcliprgn(rgn);circle(0, 0, r);for (int i = 0; i < 6; ++i){int x = cos(i * (2 * PI / 6)) * r;int y=sin(i * (2 * PI / 6)) * r;circle(x,y,r);}setcliprgn(NULL);//將剪切區域設為空DeleteObject(rgn);//銷毀區域DeleteObject(rgn1);//銷毀區域DeleteObject(rgn2);//銷毀區域getchar();closegraph();return 0;
}

?

我們接下來看并集的

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);setaspectratio(1, -1);setbkcolor(WHITE);cleardevice();setlinecolor(BLACK);setlinestyle(PS_SOLID, 10);int r = 150;HRGN rgn1 = CreateEllipticRgn(250, 250, 550, 550);//創建區域HRGN rgn2 = CreateEllipticRgn(250, 100, 550, 400);//創建區域HRGN rgn = CreateEllipticRgn(0,0,0,0);//創建區域CombineRgn(rgn, rgn1, rgn2, RGN_OR);setcliprgn(rgn);circle(0, 0, r);for (int i = 0; i < 6; ++i){int x = cos(i * (2 * PI / 6)) * r;int y=sin(i * (2 * PI / 6)) * r;circle(x,y,r);}setcliprgn(NULL);//將剪切區域設為空DeleteObject(rgn);//銷毀區域DeleteObject(rgn1);//銷毀區域DeleteObject(rgn2);//銷毀區域getchar();closegraph();return 0;
}

?

我們看看并集排除重疊區域

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{initgraph(800, 600);//創建了800*600像素的窗體setorigin(400, 300);setaspectratio(1, -1);setbkcolor(WHITE);cleardevice();setlinecolor(BLACK);setlinestyle(PS_SOLID, 10);int r = 150;HRGN rgn1 = CreateEllipticRgn(250, 250, 550, 550);//創建區域HRGN rgn2 = CreateEllipticRgn(250, 100, 550, 400);//創建區域HRGN rgn = CreateEllipticRgn(0,0,0,0);//創建區域CombineRgn(rgn, rgn1, rgn2, RGN_XOR);setcliprgn(rgn);circle(0, 0, r);for (int i = 0; i < 6; ++i){int x = cos(i * (2 * PI / 6)) * r;int y=sin(i * (2 * PI / 6)) * r;circle(x,y,r);}setcliprgn(NULL);//將剪切區域設為空DeleteObject(rgn);//銷毀區域DeleteObject(rgn1);//銷毀區域DeleteObject(rgn2);//銷毀區域getchar();closegraph();return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/12958.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/12958.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/12958.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Go 注釋生成 api文檔

在 Go 語言中&#xff0c;通常會使用 godoc 工具來從注釋中生成 API 文檔。godoc 是 Go 官方提供的文檔生成工具&#xff0c;它可以解析 Go 源代碼中的注釋&#xff0c;并生成在線的、可交互的文檔。 為了使用 godoc 生成 API 文檔&#xff0c;你需要遵循一些特定的注釋格式。…

使用VMware或VirtualBox安裝eNSP Pro并使用CRT連接設備

文章目錄 使用Oracle Virtual Box安裝eNSP Pro創建虛擬機配置網卡配置帶外管理網絡 使用VMware Workstation安裝eNSP Pro轉換文件格式及虛擬磁盤模式配置網卡創建虛擬機配置使用CRT連接管理設備 前一段時間是開放了eNSP Pro的賬號權限&#xff0c;但是在寫博客時&#xff0c;權…

2024OD機試卷-字符串分割(二) (java\python\c++)

題目:字符串分割(二) 題目描述 給定一個非空字符串S,其被N個‘-’分隔成N+1的子串,給定正整數K,要求除第一個子串外,其余的子串每K個字符組成新的子串,并用‘-’分隔。 對于新組成的每一個子串,如果它含有的小寫字母比大寫字母多,則將這個子串的所有 大寫字母轉換為小…

27.哀家要長腦子了!

目錄 1.316. 去除重復字母 - 力扣&#xff08;LeetCode&#xff09; 2. 1209. 刪除字符串中的所有相鄰重復項 II - 力扣&#xff08;LeetCode 哎喲 煩死了 剛剛不小心退出又沒保存 又要寫一遍 煩死了 最近刷題不得勁啊 感覺這腦子沒長一點 1.316. 去除重復字母 - 力扣&am…

(實測驗證)【移遠EC800M-CN 】GNSS功能打開和關閉關閉步驟驗證

引言 本文章使用自研“超小體積TTL轉4GGPS集成模塊”進行實測驗證&#xff1b; 一、打開GNSS功能 步驟一、通過 ATQGPSCFG 配置 GNSS 參數 &#xff08;1&#xff09;該命令用于查詢和配置 GNSS 不同的設置&#xff0c;包括 NMEA 語句輸出端口、NMEA 語句的輸出類型等。 1.1…

NSSCTF | [SWPUCTF 2021 新生賽]easyupload2.0

先傳一個普通的一句話木馬試一試 GIF89a <?php eval($_POST[shell]);?> 可以看到回顯&#xff0c;不允許上傳php文件。 使用Burpsuite抓包只修改ContentType后發現也不能繞過&#xff0c;說明服務器使用了黑名單后綴限制&#xff0c;那么我們可以使用其他的后綴代替ph…

RPA的實施過程通常包括哪些步驟?

RPA&#xff08;Robotic Process Automation&#xff09;的實施過程通常涉及一系列詳細的步驟&#xff0c;旨在確保自動化項目的成功部署和運行。以下是RPA實施過程的一般步驟&#xff1a; ### 1. 需求分析與目標設定 實施RPA的第一步是進行需求分析&#xff0c;明確企業希望通…

電路板維修【四】

【開關電源輸出電壓偏低不穩&#xff0c;用示波器立馬鎖定故障范圍】&#xff1a;https://www.bilibili.com/video/BV1pf421D73K?vd_source3cc3c07b09206097d0d8b0aefdf07958 可以用示波器查看MOS的輸出波形來查看其是否損壞&#xff1a; 電源芯片的供電電壓來回跳變&#xf…

嵌入式C語言與人工智能融合開發高級教程:實現手勢識別系統

目錄 文章主題環境準備人工智能與嵌入式系統基礎代碼示例&#xff1a;實現手勢識別系統應用場景&#xff1a;智能家居與穿戴設備問題解決方案與優化 1. 文章主題 文章主題 本教程將詳細介紹如何在STM32嵌入式系統中使用C語言實現手勢識別系統&#xff0c;特別是如何在資源受…

基于卷積神經網絡CNN,使用二維卷積Conv2D實現MNIST數字識別的四種方法

前言 系列專欄&#xff1a;機器學習&#xff1a;高級應用與實踐【項目實戰100】【2024】?? 在本專欄中不僅包含一些適合初學者的最新機器學習項目&#xff0c;每個項目都處理一組不同的問題&#xff0c;包括監督和無監督學習、分類、回歸和聚類&#xff0c;而且涉及創建深度學…

ROS 2邊學邊練(48)-- 將URDF與robot_state_publisher一起使用

前言 本篇將完成一個行走的機器人&#xff0c;并以tf2消息的方式實時發布機器人狀態&#xff0c;以便我們在Rviz中同步查看。 首先&#xff0c;我們創建描述機器人裝配的URDF模型。接下來&#xff0c;我們編寫一個節點&#xff0c;用于模擬運動并發布JointState和位姿變換。然后…

C-函數的由淺入深

1.函數的定義 數據類型 函數名 &#xff08;【數據類型 形參名&#xff0c;數據類型 形參名&#xff0c; …】&#xff09; 2.函數的傳參 值傳遞 地址傳遞 全局變量 3.函數的調用 嵌套調用 遞歸 4.函數與數組 5.函數與指針 指針函數 函數指針 函數指針數組 函數的定義 #inclu…

醉了,面個功能測試,還問我Python裝飾器

Python 裝飾器是個強大的工具&#xff0c;可幫你生成整潔、可重用和可維護的代碼。某種意義上說&#xff0c;會不會用裝飾器是區分新手和老鳥的重要標志。如果你不熟悉裝飾器&#xff0c;你可以將它們視為將函數作為輸入并在不改變其主要用途的情況下擴展其功能的函數。裝飾器可…

dhcp(接口和全局地址池模式)

接口地址池和全局地址池 dhcp應用 1.全部開啟dhcp功能 2.ar5 0口接口地址池 1口全局地址池 3.ar6和ar7配置&#xff0c;查看能否自動獲取ip 左右不同兩個網絡&#xff0c;接口和全局地址池的區別 部分截圖 ar6 ar7 ar5

(實測驗證)【移遠EC800M-CN 】TCP 透傳

引言 本文章使用自研“超小體積TTL轉4GGPS集成模塊”進行實測驗證&#xff1b; 1、配置移遠EC800M-CN TCP 透傳 串口助手發送&#xff1a; ATQIOPEN1,0,"TCP","36.137.226.30",39755,0,2 //配置服務器地址和端口號&#xff1b; 4G模組返回…

07-Fortran基礎--Fortran指針(Pointer)的使用

07-Fortran基礎--Fortran指針Pointer的使用 0 引言1 指針&#xff08;Poionter&#xff09;的有關內容1.1 一般類型指針1.2 數組指針1.3 派生類(type)指針1.4 函數指針 2 可運行code 0 引言 Fortran是一種廣泛使用的編程語言&#xff0c;特別適合科學計算和數值分析。Fortran 9…

java代碼混淆工具ProGuard混淆插件

java代碼混淆工具ProGuard混淆插件 介紹 ProGuard是一個純java編寫的混淆工具&#xff0c;有客戶端跟jar包兩種使用方式。可以將程序打包為jar&#xff0c;然后用工具進行混淆&#xff0c;也可以在maven中導入ProGuard的插件&#xff0c;對代碼進行混淆。 大家都知道 java代…

【華為OD機試-C卷D卷-200分】田忌賽馬(C++/Java/Python)

【華為OD機試】-(A卷+B卷+C卷+D卷)-2024真題合集目錄 【華為OD機試】-(C卷+D卷)-2024最新真題目錄 題目描述 給定兩個只包含數字的數組a,b,調整數組 a 里面的數字的順序,使得盡可能多的a[i] > b[i]。 數組a和b中的數字各不相同。 輸出所有可以達到最優結果的a數組的…

SadTalker 自定義容器化部署配置

Docker 環境檢查 執行docker info 查看環境種是否有安裝docker&#xff0c;否則首先安裝好docker 運行環境。在線環境安裝執行執行兩條指令即可 sudo apt install docker sudo apt-get install docker-ce sudo apt-get install docker-composesudo systemctl restart dockerG…

langchain源碼

itemgetter&#xff1a;返回一個函數&#xff0c;函數取輸入dict的某個指定key Runnable 的基本方法有 invoke、 batch、 await、 ainvoke、 abatch 同步轉異步 Runnable 還具有的方法&#xff1a;bind、 with_config。 input_schema 屬性、output_schema 屬性 with_retry方…