1. 問題的提出
在一些數據庫管理系統或辦公自動化和統計類軟件中,一般具有繪制三維視圖的功能。使用時通常要求在給出的表格中輸入繪圖的數據及視角、比例尺等參數。這只適用於小批量的統計數據繪制統計三維視圖。在地質、地貌、氣象、水文、交通、林業等許多領域,需要描述的某一量通常具有空間分布特征,這種空間分布數據的數量一般十分龐大,當使用上述三維視圖軟件繪圖時經常會遇到輸數表格容納不下的問題,而且按表格重新輸入數據也容易出錯和耗費許多人力。
三維視圖的繪制及相應繪圖數據的組織並不是一件十分困難的事,使用少量程序代碼就可以實現這一目標。本文將介紹一種以C++語言實現大批量數據繪制三維視圖的簡易方法。該法的關鍵技術在於:(1)以FoXPro數據庫管理系統整理繪圖數據並制成可為C++語言包括和調用的.h文件;(2)在繪制三維視圖中,以“多邊形法”進行需遮蔽線段的消隱。
2. 繪圖數據的准備
繪圖的原始數據來自FoxPro(或FoxBase)數據庫管理系統。可以將某幅圖的數據置於一個一維數組中,並包括在一個.h文件中。這樣只要在C++的繪三維視圖程序首包括該頭文件,就可以在程序的任何位置調用這些數據。例如有一個數據串:3,8,10,11,27,6,……,設存放數組為A,數據文件名為data.h,在data.h中,該數據串的存放形式為:
A={ 3,8,10,11, 27, 6, : :};
這些數據可由FoxPro的.dbf文件拷貝得到。當然,在拷貝前還需經過簡單的加工。設在.dbf文件中,待繪圖數據所在的字段為DT1,此時可增設一個字段DH(逗號),並將該字段的內容全以“,”替換,然後以如下命令拷貝到data.h文件中: copy to data.h field DT1,DH dele with blank 隨後打開data.h文件,在數據首加上“A={”,在數據尾加上“ };”即可。
3. 繪三維視圖編程基本思想
繪三維視圖的關鍵技術在“消隱”,即消去在三維觀察時應該被擋住看不見的線。在有關“計算機圖形學”的書籍中所介紹的消隱法多為“計算法”,即由當前數據點行計算在已繪出的線條中哪些應該隱去,再清除這些線條。筆者自己設計了一種簡便新穎的消隱法(這裡姑且稱之為“多邊形法”),不僅程序代碼簡單,而且這種消隱法的原理也十分簡潔明了。現將其基本思想及運算步驟介紹如下:
3.1 首排數據繪X方向網線。以line函數將首排數據點連線;
3.2 繪Y方向網線。將第2排與第1排在Y方向相對應的數據點連線;
3.3 以“多邊形法”做消隱。據第2排點的數據以背景色塗刷一個多邊形,這樣,可能被第2排數據點連線所遮蔽的線條(即應消隱的線)即被擦除;
3.4 第2排數據繪X方向網線。以line函數將第2排數據點連線;
3.5 重復步驟3.2~3.4,直至繪完全圖。
4. 繪三維視圖源程序(for Windows)
draw3d.cpp
#include
#include "data.h"
int PASCAL WinMain (HANDLE, HANDLE, LPSTR, int);
long FAR PASCAL WindowProc (HWND, Word, WORD, LONG);
int mv[15625]; // mv[ ] 為繪圖數據數組,存於data.h中
HANDLE hInst;
int PASCAL WinMain (HANDLE hInstance, HANDLE
hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
…… //此處略去了創建窗口的代碼塊
}
long FAR PASCAL WindowProc (HWND hWnd, WORD message,
WORD wParam, LONG lParam)
{
HDC hDC;
PAINTSTRUCT ps;
HBRUSH hOldBrush;
int i=0,j=0;
int yy[MAXPTS]; //MAXPTS為繪圖行或列數,在data.h中定義
static POINT PointTable[MAXPTS+2];
switch (message)
{ // 定義畫筆或畫刷
static LOGPEN lpBlack={PS_SOLID,1,1,RGB(0,0,0)};
static LOGPEN lpGreen={PS_SOLID,1,1,RGB(0,255,0)};
static LOGPEN lpWhite={PS_SOLID,1,1,RGB(255,255,255)};
HBRUSH hBlackBrush;
HBRUSH hWhiteBrush;
HPEN hGreenPen;
HPEN hWhitePen;
HDC hDC;
PAINTSTRUCT PtStr;
LoadString (hInst, IDS_CAPTION, szCaption, 35);
return 0;
case WM_PAINT:
hDC = BeginPaint (hWnd, &PtStr);
SetMapMode(hDC,MM_TEXT);
hBlackPen=CreatePenIndirect(&lpBlack);
hGreenPen=CreatePenIndirect(&lpGreen);
hWhitePen=CreatePenIndirect(&lpWhite);
hBlackBrush=GetStockObject(BLACK_BRUSH);
hWhiteBrush=GetStockObject(WHITE_BRUSH);
hOldBrush = SelectObject (hDC,GetStockObject
(NULL_BRUSH));
{
yy[j]=MOVE+j*SCALE1; //MOVE為繪圖起始點Y坐標,在data.h中定義
for(i=0;i
{
(未完。。。)
PointTable[i].x=i*SCALE2+j*SCALE4; // 形成多邊形頂點
數組
PointTable[i].y=yy[j]-(PointTable
[i].x-PointTable[0].x)*ANGLE-(mv[j*MAXPTS+i]
*SCALE3); //SCALE2和SCALE4分別為X和Y方向的縮放系數
if(j>0) //SCALE3為繪圖數據(Z方向)的縮放系數
{ //ANGLE為視角,均在data.h中定義
SelectObject(hDC,hGreenPen);
MoveTo(hDC,mx[i],my[i]);
LineTo(hDC,PointTable[i].x,PointTable[i].y); // 繪 y 方 向 網 線
}
}
PointTable[MAXPTS].x=PointTable[MAXPTS-1].x;
PointTable[MAXPTS].y=PointTable[MAXPTS-1].y+20;
PointTable[MAXPTS+1].x=PointTable[0].x;
PointTable[MAXPTS+1].y=PointTable[0].y+20;
if(j==(MAXPTS-1))
{
SelectObject(hDC,hWhitePen);
SelectObject(hDC,hWhiteBrush);
Polygon(hDC,PointTable,MAXPTS); // 消 隱
}
else
{
SelectObject(hDC,hBlackPen);
SelectObject(hDC,hBlackBrush);
Polygon(hDC,PointTable,MAXPTS); // 消 隱
}
for(i=0;i
{
mx[i]=PointTable[i].x; //將前排點數據存於mx[i]
my[i],
my[i]=PointTable[i].y; // 留待繪y方向網線
}
for(i=0;i<(MAXPTS-1);i++)
{
SelectObject(hDC,hGreenPen);
MoveTo(hDC,PointTable[i].x,PointTable[i].y);
LineTo(hDC,PointTable[i+1].x,PointTable[i+1].y);//繪 x方向網線
}
}
SelectObject (hDC, hOldBrush);
EndPaint (hWnd, &PtStr);
return 0;
case WM_DESTROY:
ostQuitMessage (0);
return 0;
default:
break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
5. 結論
繪圖數據及縮放、視角等參數皆存於data.h文件中,或在該文件中說明,所以當繪圖參數等內容變化時,只要修改或重新制作data.h文件即可。由此可見該程序具有使用靈活,可容繪圖數據量大等優點,可用於各種空間分布數據三維視圖的繪制,尤其適合於大數據量繪圖。