我們可以表列出 -π 到 π 之間任意數值對應之函數值來解釋這個函數, 不過要讓別人瞭解這個 函數最好的方式還是透過繪圖, 本範例中分別運用控制台文字模式 ( Visual C++ / dev C++) 和 BGIm 函式庫的圖形模式 (Visual C++ / dev C++) 來繪製 sin() 函數:
範例執行程式:
這是一個二維平面上的圖形, x 軸範圍在 -π 到 π 之間, y 軸範圍在 -1 到 1 之間, 因為這是一個連續函數, 所以不論 x 軸或是 y 軸, 我們都知道其上應該有無窮多個點。
但是在電腦螢幕上要顯示這樣子的圖形, 不可能也不需要使用無窮多個點,
不可能的原因是螢幕的解析度有限, 在文字 模式視窗只能顯示 80 個字元寬、24 個字元高, 每一個方格裡你只能顯示一個字元或是不顯示, 沒有太多的選擇。 在簡單的 BGIm 圖形模式視窗中允許你在指定的 寬度及高度 的視窗中作圖, 每一個點除了允許你畫點或是不畫點之外, 也容許你用 16 個顏色來畫點。
不需要使用無窮多點的原因是: 你的眼睛不夠好, 根本無法在螢幕上分辨距離太近的點。
下圖是在文字模式視窗中繪製的 sine 函數示意圖:
你可以想像畫面中分為 24 x 80 個不重疊的長方形小方格, 每一個小方格裡可以顯示一個字元, 例如 '-' 號或是 '*' 號或是 '.', 上圖表示之圖形雖然不夠細緻, 也還勉強可以感覺此曲線之走向。
下圖在 BGIm 繪圖模式視窗中繪製同樣的 sine 函數:
由於解析度大大提高, 在上面視窗中繪製的曲線, 你已經慢慢感覺不出來它是折線了。
實數平面 寬:2π 高:2 |
文字模式 寬:80 高:24 |
繪圖模式視窗 寬:640 高:480 |
---|---|---|
(x,y) | (x1,y1) | (x2,y2) |
(0, 0) | (40, 12) | (320, 240) |
(π, 0) | (79, 12) | (639, 240) |
(-π, 0) | (1, 12) | (1, 240) |
(0, 1) | (40, 1) | (320, 1) |
(0, -1) | (40, 23) | (320, 479) |
一般化的公式應該是
實數平面 寬:2π 高:2 |
文字模式 寬:80 高:24 |
繪圖模式視窗 寬:640 高:480 |
---|---|---|
x y |
x1 = x / π * 39 + 40 y1 = -y * 11 + 12 |
x2 = x / π * 319 + 320 y2 = -y * 239 + 240 |
請注意:
double x = 2.6, y = 2.4; int ix, iy; ix = (int) (x + 0.5); iy = (int) (y + 0.5);則整數變數 i 內的數值為 3, j 內的數值為 2。
其中一種方法是使用 utilwin32.h utilwin32.cpp 中的 void gotoxy(int x, int y); 函式將游標移到第 x 行, 第 y 列, 再以 stdio.h 函式庫中的 int putchar(int c); 函式再該位置畫出字元, 例如:
會在視窗的左上角印出一個 * 字元。
由於在控制台視窗的文字模式下 x 軸最多就只能有 80 個點, 為了讓正負對稱, 我們只畫 79 個點, 因此我們最多只需要去求出這麼多 sin() 函數的數值即可, 也就是說在 -π 到 π 之間只要畫 79 個點, 其間隔為 2 π / 78, 這些點的位置為 π/39*i i=-39,-38.....38,39, 做這件事情的程式如下:
double x, y; for (i=-39; i<=39; i++) { x = PI / 39 * i; y = sin(x); // library function in math.h ix = i + 40; iy = (int) (y * 11 + 12 + 0.5); gotoxy(ix,iy); putchar('*'); }請注意:
在繪製上面 sine 函數之前先繪出座標軸如下:
for (i=-39; i<=39; i++) // x-軸 { gotoxy(i+40, 12); putchar('-'); } for (i=-11; i<=11; i++) // y-軸 { gotoxy(40, 12+i); putchar('|'); } gotoxy(40, 12); // 原點 putchar('+');
Visual C++ 6, 2008, 2010 中命令列編譯如下: cl SineText.cpp utilwin32.cpp
Dev C++ 5.11 產生多檔案專案, 加入 SineText.cpp 及 utilwin32.cpp, 編譯並執行
gcc 4.9.2 中命令列編譯如下: g++ -static SineText.cpp utilwin32.cpp
這個圖形界面原先是在 Turbo C 和 Borland C 中一個簡單的圖形界面, 拿來練習還蠻不錯的, 不需要一開始就學習使用 Win32 裡比較複雜的圖形 API
1. 引入檔: (請以滑鼠右鍵另存連結/目標)下載 graphics.h (請注意不需要再使用 utilwin32.h 了, 這兩個裡面的 delay() 函式是重複的)
Visual C++ 6 拷貝至 C:\Program Files\Microsoft Visual Studio\VC98\Include
Visual C++ 2008 拷貝至 C:\Program Files\Microsoft Visual Studio 9\VC\include
Visual C++ 2010 拷貝至 C:\Program Files\Microsoft Visual Studio 10.0\VC\include
devC++ 4.9.9.2 (g++ 3.4.2) 拷貝至 C:\Dev-Cpp\include (請注意 BGIm 需要用 sstream, 需要用 g++ 編譯器, 你自己的程式也要使用 .cpp 作為副檔名)
MinGW g++ 4.8.1-4 (32bit) 拷貝至 C:\MinGW\include (請注意 BGIm 需要用 sstream, 需要用 g++ 編譯器, 你自己的程式也要使用 .cpp 作為副檔名)
devC++ 5.7.1 (g++ 4.8.1, 64bit) 拷貝至 C:\Program Files (x86)\Dev-Cpp\MinGW64\include (請注意 BGIm 需要用 sstream, 需要用 g++ 編譯器, 你自己的程式也要使用 .cpp 作為副檔名)
devC++ 5.11 (g++ 4.9.2, 64bit) 拷貝至 C:\Program Files (x86)\Dev-Cpp\MinGW64\include (請注意 BGIm 需要用 sstream, 需要用 g++ 編譯器, 你自己的程式也要使用 .cpp 作為副檔名)
MinGW (g++ 4.8.1, 64bit) 拷貝至 C:\MinGW\include (請注意 BGIm 需要用 sstream, 需要用 g++ 編譯器, 你自己的程式也要使用 .cpp 作為副檔名)
2. 函式庫 (請以滑鼠右鍵點選適當版本的 libbgi.lib 另存連結/目標)
Visual C++ 6 下載 libbgi.lib, 拷貝至 C:\Program
Files\Microsoft Visual Studio\VC98\Lib
Visual C++ 2008 下載 libbgi.lib, 拷貝至 C:\Program
Files\Microsoft Visual Studio 9\VC\Lib
Visual C++ 2010 下載 libbgi.lib, 拷貝至 C:\Program
Files\Microsoft Visual Studio 10.0\VC\Lib
dev C++ 4.9.9.2 (g++ 3.4.2, 32bit) 下載 libbgi.a,
拷貝至 C:\Dev-Cpp\lib
MinGW (g++ 4.8.1-4, 32bit) 下載 libbgi.a,
拷貝至 C:\MingGW\lib
dev C++ 5.7.1 (g++ 4.8.1, 64bit) 下載 libbgi.a,
拷貝至 C:\Program Files (x86)\Dev-Cpp\MinGW64\lib
dev C++ 5.11 (g++ 4.9.2, 64bit) 下載 libbgi.a,
拷貝至 C:\Program Files (x86)\Dev-Cpp\MinGW64\lib (工具/編譯器選項/一般/在連結器命令列加入以下的命令)
MinGW (g++ 4.8.1, 64bit) 下載 libbgi.a,
拷貝至 C:\MinGW\lib
3. 測試程式 testBGIm.cpp (下載完上面兩個檔案以後, 請以滑鼠右鍵另存連結/目標
下載此測試程式,編譯並且測試簡單的繪圖功能)
4. 編譯器/連結器參數 (將下面的 xxx.cpp 改為你自己的應用程式名稱)
Visual C++ 6: cl -GX xxx.cpp libbgi.lib gdi32.lib
comdlg32.lib uuid.lib oleaut32.lib ole32.lib user32.lib
Visual C++ 2008: cl -EHsc xxx.cpp libbgi.lib gdi32.lib
comdlg32.lib uuid.lib oleaut32.lib ole32.lib user32.lib
Visual C++ 2010: cl -EHsc xxx.cpp libbgi.lib gdi32.lib
comdlg32.lib uuid.lib oleaut32.lib ole32.lib user32.lib
dev C++ 4.9.9.2: -lbgi -lgdi32 -lcomdlg32 -luuid
-loleaut32 -lole32
dev C++ 5.7.1, dev C++ 5.11: -lbgi -lgdi32 -lcomdlg32
-luuid -loleaut32 -lole32 -Wno-write-strings (工具/編譯器選項/一般/在連結器命令列加入以下的命令)
MinGW (g++ 3.4.2, 32bit): g++ testBGIm.cpp -o testBGIm.exe -lbgi
-lgdi32 -lcomdlg32 -luuid -loleaut32 -lole32
MinGW (g++ 4.8.1, 64bit): g++ testBGIm.cpp -o testBGIm.exe -lbgi
-lgdi32 -lcomdlg32 -luuid -loleaut32 -lole32 -Wno-write-strings
5. Visual C++ 6 命令列編譯: 下載 bgi.exe, 拷貝至 C:\Program Files\Microsoft Visual Studio\VC98\bin, 以 bgi xxx.cpp 編譯程式
6. 說明文件 bgi.chm (Windows 中如果看不到內容的話, 請以滑鼠右鍵點選檔案 bgi.chm /內容/取消封鎖) (線上版本)
注意:如果你沒有權限拷貝檔案到系統裡, 把 graphics.h 和 libbgi.a (libbgi.lib) 一起和你的程式 xxx.cpp 放在同一個資料匣, 程式裡改成
#include "graphics.h"
Visual C++ 6: cl -GX xxx.cpp libbgi.lib gdi32.lib comdlg32.lib uuid.lib oleaut32.lib ole32.lib user32.lib
Visual C++ 2008/2010: cl -EHsc xxx.cpp libbgi.lib gdi32.lib comdlg32.lib uuid.lib oleaut32.lib ole32.lib user32.lib
dev C++ 4.9.9.2 (g++ 3.4.2): -L. -lbgi -lgdi32 -lcomdlg32 -luuid -loleaut32 -lole32
dev C++ 5.7.1 (g++ 4.8.1, 32bit,64bit), dev C++ 5.11 (g++ 4.9.2): -L. -lbgi -lgdi32 -lcomdlg32 -luuid -loleaut32 -lole32 -Wno-write-strings
initwindow(640, 480, "First Sample"); // graphics.h 進入繪圖模式, 開啟 640 x 480 大小的繪圖視窗 ... 繪圖動作 ... closegraph(); // graphics.h 中結束繪圖模式, 這一列請放在 system("pause") 之後
與
的效果完全一樣, moveto(200, 20) 將游標位置 CP 移動到 (200, 20) 的地方, lineto(200, 80) 則由 CP 的位置畫直線到 (200, 80), 並設定 CP 為 (200, 80)。
使用 lineto() 函式畫連續線段比起 line() 函式最大的好處就是程式中不需要記錄上一點的座標, 而由繪圖系統中的 CP 來記住。
注意:
setcolor(LIGHTGREEN); line(320, 0, 320, 479); outtextxy(100, 200, "hello"); setcolor(LIGHTRED); outtextxy(120, 200, "world");就會 畫出一條亮綠色的直線, 亮綠色的文字 hello 以及紅色的文字 world
畫點的部份都以畫線來取代, 程式如下:
ix = (int) ((x = -PI) / PI * 319 + 320 + 0.5); iy = (int) (-sin(x) * 239 + 240 + 0.5); moveto(ix, iy); for (i=-318; i<=319; i++) { x = PI / 319 * i; y = sin(x); ix = i + 320; iy = (int) (-y * 239 + 240 + 0.5); lineto(ix, iy); }