C++ 實習測試: 筆劃 (Stroke) 類別製作 |
時間: 80分鐘 (10:40 上傳時間截止) |
在這個測試裡, 我們要製作一個「筆劃」的類別, 目的是支援一個「1052Quiz1 隨意筆」的繪圖程式來運作, 這個程式執行起來的畫面如下: 你可以點上面的連結 (或是上面這張圖) 在你的機器上執行 (如果沒有安裝 vc2010, 需要有 vc10 redistributable DLLs, 請下載、解壓縮、拷貝 32bit\*.dll 或是 64bit\*.dll 到 c:\windows\system32) 你可以運用滑鼠在視窗裡隨意繪圖, 例如: 這個程式和 Windows 的小畫家不一樣, 小畫家是一個點陣圖的繪圖程式, 整個視窗是一個畫布, 畫出來的都是獨立的點, 每一筆並不是一個物件, 你不能再用滑鼠去點一個筆劃, 去修改原先的東西; 我們這個程式希望是一個向量化的繪圖程式, 所以我們希望用筆劃為單位來存放資料, 像上圖裡面就只有兩個筆劃。這個程式還沒有完整的功能, 目前可以開多個視窗、分割視窗、畫粗線條、畫細線條、清除畫布、存檔、讀檔、列印、預覽列印等等,複製/貼上、選取筆劃、選取區域中所有筆劃、刪除所選取筆劃、修改所選的筆劃的粗細、修改顏色、移動某一筆劃、放大/縮小、移到最上層、下移一層、上移一層,...都還沒有寫, 別擔心, 不是請你現在寫這些, 只是希望你設計一個筆劃的類別來儲存一筆所畫出來的資料, 以便支援這個程式。 這個程式的存檔功能在設計的時候, 存出去的 *.qz1 檔案是二進位模式的檔案, 在其它文字編輯器裡面讀出來會是亂碼, 不過再由這個程式讀進來的話還是可以顯示的。為了這次考試, 我們額外設計了一個功能是用文字模式來儲存 *.txt 的文字檔案如下圖: 選取上面的選單以後可以看到 Windows 標準的檔案選取對話盒: 填入檔案名稱 (例如 CS)、按下存檔可以把筆劃的資料存在 CS.txt 中 這個檔案中有上圖中筆劃的資料 (你可以自己產生資料檔案, 也可以下載下面的文字檔案) 以這個檔案來說, 裡面主要依序包含兩個筆劃的資料,格式說明如括號中文字: 2 (本檔案裡筆劃總數) 64 -45 140 -128 (「含括第一筆的最小長方形邊框」, 左上右下, 請見下圖說明) 5 (第一筆的粗細) 205 (第一筆的點數) 134 -60 (第一筆的第一點的 x 座標與 y 座標) 133 -60 (第一筆的第二點的 x 座標與 y 座標) 131 -57 。。。 。 。 。 126 -103 「含括某一筆劃的最小長方形邊框」所代表的意思如下圖: 是含括那一筆劃圖形的最小長方形 - (left, top, right, bottom), 也就是所有這個筆劃的圖形的 x 座標的範圍是 left+width ≤ xi < right-width, y 座標的範圍是 bottom+width ≤ yi < top-width, 這裡因為筆劃有寬度 width, 所以我們直接加上筆劃的寬度來簡單近似這個最小長方形, 也就是最小的長方形是覆蓋那些點座標的長方形四周再放大 width 格的那個長方形, 請注意所有的點的 x 座標都小於 right-width, 所有的點的 y 座標都大於 bottom+width。 |
下面是運用 stdio.h 函式庫來開啟這個檔案並且讀取資料的 C 程式, 程式直接把資料讀到一個自己定義的結構 struct Point 的陣列中 #include <stdio.h> #include <assert.h> struct Point { int x; int y; }; struct BoundingRect { int left; int top; int right; int bottom; }; int isEqual(BoundingRect br1, BoundingRect br2); void calcBoundingRect(int length, int width, Point stroke[], BoundingRect *br); int main() { FILE *fp; int i, j, nStrokes; int widths[2]; int lengths[2]; BoundingRect brs[2], mybrs[2]; Point strokes[2][500]; fp = fopen("CS.txt", "r"); if (fp==0) { printf("無法開啟 CS.txt\n"); return 1; } fscanf(fp, "%d", &nStrokes); for (i=0; i<nStrokes; i++) { fscanf(fp, "%d%d%d%d", &brs[i].left, &brs[i].top, &brs[i].right, &brs[i].bottom); fscanf(fp, "%d", &widths[i]); fscanf(fp, "%d", &lengths[i]); for (j=0; j<lengths[i]; j++) fscanf(fp, "%d%d", &strokes[i][j].x, &strokes[i][j].y); calcBoundingRect(lengths[i], widths[i], strokes[i], &mybrs[i]); printf("%d %d %d %d\n", brs[i].left, brs[i].top, brs[i].right, brs[i].bottom); printf("%d %d %d %d\n", mybrs[i].left, mybrs[i].top, mybrs[i].right, mybrs[i].bottom); assert(isEqual(brs[i], mybrs[i])); } fclose(fp); return 0; } int isEqual(BoundingRect br1, BoundingRect br2) { 。。。 } void calcBoundingRect(int length, int width, Point stroke[], BoundingRect *br) { // 含括該筆劃圖形所有點的最小長方形, 也就是所有這個筆劃圖形的 x // 座標的範圍是 left+width ≤ xi < right-width, y 座標的範圍是 // bottom+width ≤ yi < top-width, 這裡因為筆劃有寬度 width, // 所以我們直接加上筆劃的寬度來簡單近似這個最小長方形 } |
請撰寫一個 C++ 程式, 運用 iostream 開啟檔案並且讀取資料, 同時設計一個 Stroke 類別, 這個類別需要管理一筆劃裡面所有的點, 這個類別以及程式的要求如下:
|
考試時間: 80分鐘 (10:40 上傳時間截止)
|
將所完成的 project (只需保留 .cpp, .h, .sln 以及 .vcxproj 檔案即可; 刪除掉 .suo, .sdf, .filters, .users, debug\ 資料匣, 以及 ipch\ 資料匣下的所有內容) 以 zip/rar/7zip 程式將整個資料匣壓縮起來, 在「考試作業」繳交區選擇 Labtest1上傳 |
後續: 接下去能做的事情還蠻明顯的, 就是把整個視窗版的程式完成, 不過我們這學期的課程已經塞進去太多東西了, 不太可能在課程或是實習裡面安排時間講這些東西 (期中考後有一次實習會讓你配合一個視窗界面來寫程式), 如果有同學有興趣知道更詳細的設計方法, 可以讓我知道, 需要另外安排時間介紹。 |
回
C++ 物件導向程式設計課程
首頁
製作日期: 03/30/2017 by 丁培毅 (Pei-yih Ting) E-mail: pyting@mail.ntou.edu.tw TEL: 02 24622192x6615 海洋大學 電機資訊學院 資訊工程學系 Lagoon |