四、Windows图形处理—绘制填入区域(Polygon函数和多边形填入方
我已经讨论过了前五个区域填入函数,Polygon是第六个画带边界框的填入图形的函数,该函数的呼叫与Polyline函数相似:
Polygon (hdc, apt, iCount) ;
        
其中,apt参数是POINT结构的一个数组,iCount是点的数目。如果该数组中的最后一个点与第一个点不同,则Windows将会再加一条线,将最后一个点与第一个点连起来(在Polyline函数中,Windows不会这么做)。PolyPolygon函数如下所示:
PolyPolygon (hdc, apt, aiCounts, iPolyCount) ;
        
该函数绘制多个多边形。最后一个参数给出了所画的多边形的个数。对于每个多边形,aiCounts数组给出了多边形的端点数。apt数组具有全部多边形的所有点。除传回值以外,PolyPolygon在功能上与下面的代码相同:
for (i = 0, iAccum = 0 ; i < iPolyCount ; i++)
        
{
        
    Polygon (hdc, apt + iAccum, aiCounts[i]) ;
        
    iAccum += aiCounts[i] ;
        
}
        
对于Polygon和PolyPolygon函数,Windows使用定义在设备内容中的目前画刷来填入这个带边界的区域。至于填入内部的方式,则取决于多边形填入方式,您可以用SetPolyFillMode函数来设定:
SetPolyFillMode (hdc, iMode) ;
        
内定情况下,多边形填入方式是ALTERNATE,但是您可以将它设定为WINDING。两种方式的区别参见图5-15所示。
	
首先,ALTERNATE和WINDING方式之间的区别很容易察觉。对于ALTERNATE方式,您可以设想从一个无穷大的封闭区域内部的点画线,只有假想的线穿过了奇数条边界线时,才填入封闭区域。这就是填入了星的角而中心没被填入的原因。
五角星的例子使得WINDING方式看起来比实际上更简单一些。在绘制单个的多边形时,大多数情况下,WINDING方式会填入所有封闭的区域。但是也有例外。
在WINDING方式下要确定一个封闭区域是否被填入,您仍旧可以设想从那个无穷大的区域画线。如果假想的线穿过了奇数条边界线,区域就被填入,这和ALTERNATE方式一样。如果假想的线穿过了偶数条边界线,则区域可能被填入也可能不被填入。如果一个方向(相对于假想线)的边界线数与另一个方向的边界线数不相等,就填入区域。
例如,考虑图5-16中的物体。在线的箭头指出了画线的方向。两种方式都会填入三个封闭的L形区域,号码从1到3。号码为4和5的两个小内部区域,在ALTERNATE方式下不会被填入。但是,在WINDING方式下,号码为5的区域会被填入,因为从区域内必须穿过两条相同方向的线才能到达图形外部。号码为4的区域不会被填入,因为必须穿过两条方向相反的线。
如果您怀疑Windows没有这么聪明,那么程序5-5 ALTWIND会展示给您看。
	
程序5-5  ALTWIND
        
ALTWIND.C
        
/*-------------------------------------------------------------------
        
    ALTWIND.C --  Alternate and Winding Fill Modes
        
                          (c) Charles Petzold, 1998
        
-------------------------------------------------------------------*/
        
#include <windows.h>
        
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
        
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
        
                                         PSTR szCmdLine, int iCmdShow)
        
{
        
    static TCHAR szAppName[] = TEXT ("AltWind") ;
        
    HWND          hwnd ;
        
    MSG           msg ;
        
    WNDCLASS      wndclass ;
        
    wndclass.style        = CS_HREDRAW | CS_VREDRAW ;
        
    wndclass.lpfnWndProc= WndProc ;
        
    wndclass.cbClsExtra   = 0 ;
        
    wndclass.cbWndExtra   = 0 ;
        
    wndclass.hInstance    = hInstance ;
        
    wndclass.hIcon        = LoadIcon (NULL, IDI_APPLICATION) ;
        
    wndclass.hCursor      = LoadCursor (NULL, IDC_ARROW) ;
        
    wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
        
    wndclass.lpszMenuName= NULL ;
        
    wndclass.lpszClassName= szAppName ;
        
   
        
    if (!RegisterClass (&wndclass))
        
    {
        
    MessageBox (  NULL, TEXT ("Program requires Windows NT!"),
        
                          szAppName, MB_ICONERROR) ;
        
            return 0 ;
        
    }
        
   
        
    hwnd = CreateWindow (szAppName, TEXT ("Alternate and Winding Fill Modes"),
        
                           WS_OVERLAPPEDWINDOW,
        
                           CW_USEDEFAULT, CW_USEDEFAULT,
        
                           CW_USEDEFAULT, CW_USEDEFAULT,
        
                           NULL, NULL, hInstance, NULL) ;
        
   
        
            ShowWindow (hwnd, iCmdShow) ;
        
            UpdateWindow (hwnd) ;
        
   
        
    while (GetMessage (&msg, NULL, 0, 0))
        
    {
        
            TranslateMessage (&msg) ;
        
            DispatchMessage (&msg) ;
        
    }
        
            return msg.wParam ;
        
}
        
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        
{
        
    static POINT aptFigure [10] = {10,70, 50,70, 50,10, 90,10, 90,50,
        
                               30,50, 30,90, 70,90, 70,30, 10,30 };
        
    static int    cxClient, cyClient ;
        
    HDC           hdc ;
        
    int           i ;
        
    PAINTSTRUCT   ps ;
        
    POINT         apt[10] ;
        
   
        
            switch (message)
        
    {
        
    case   WM_SIZE:
        
            cxClient = LOWORD (lParam) ;
        
           cyClient = HIWORD (lParam) ;
        
           return 0 ;
        
    case   WM_PAINT:
        
            hdc = BeginPaint (hwnd, &ps) ;
        
            SelectObject (hdc, GetStockObject (GRAY_BRUSH)) ;
        
            for (i = 0 ; i < 10 ; i++)
        
            {
        
                   apt[i].x = cxClient * aptFigure[i].x / 200 ;
        
                   apt[i].y = cyClient * aptFigure[i].y / 100 ;
        
            }
        
            SetPolyFillMode (hdc, ALTERNATE) ;
        
            Polygon (hdc, apt, 10) ;
        
            for (i = 0 ; i < 10 ; i++)
        
            {
        
                   apt[i].x += cxClient / 2 ;
        
            }
        
            SetPolyFillMode (hdc, WINDING) ;
        
            Polygon (hdc, apt, 10) ;
        
        
        
            EndPaint (hwnd, &ps) ;
        
            return 0 ;
        
        
        
    case   WM_DESTROY:
        
            PostQuitMessage (0) ;
        
            return 0 ;
        
    }
        
    return DefWindowProc (hwnd, message, wParam, lParam) ;
        
}
        
图形的坐标(划分为100×100个单位)储存在aptFigure数组中。这些坐标是依据显示区域的宽度和高度划分的。程序显示图形两次,一次使用ALTERNATE填入方式,另一次使用WINDING方式。结果见图5-17。
	
